From 22754be3bb5cae8609c0e1bce91df972c1b5ebde Mon Sep 17 00:00:00 2001 From: Jo <10510431+j178@users.noreply.github.com> Date: Mon, 27 Apr 2026 15:39:53 +0800 Subject: [PATCH 01/23] Add SchemaStore schema update script (#2019) --- scripts/update-schemastore-schema.sh | 33 ++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100755 scripts/update-schemastore-schema.sh diff --git a/scripts/update-schemastore-schema.sh b/scripts/update-schemastore-schema.sh new file mode 100755 index 000000000..856e4c929 --- /dev/null +++ b/scripts/update-schemastore-schema.sh @@ -0,0 +1,33 @@ +#!/usr/bin/env bash +set -exuo pipefail + +repo_root=$(git rev-parse --show-toplevel) +schema="$repo_root/prek.schema.json" +schemastore="$(dirname "$repo_root")/schemastore" +current_tag=$(git -C "$repo_root" describe --tags --abbrev=0) +commit_message="Update prek schema to $current_tag" +target="src/schemas/json/prek.json" + +if [[ ! -d "$schemastore/.git" ]]; then + mkdir -p "$(dirname "$schemastore")" + gh repo clone j178/schemastore "$schemastore" -- --depth=1 +fi + +( + cd "$schemastore" + + git fetch upstream master + git switch master + git reset --hard upstream/master + git push --force-with-lease origin master + + cp "$schema" "$target" + prek run prettier --files "$target" || true + if git diff --quiet -- "$target"; then + echo "No changes to commit" + exit 0 + fi + git add "$target" + git commit -m "$commit_message" -- "$target" + git push origin master +) From 6b9db8670df6118a6b0f0031700da032a0b30706 Mon Sep 17 00:00:00 2001 From: Jo <10510431+j178@users.noreply.github.com> Date: Mon, 27 Apr 2026 16:15:39 +0800 Subject: [PATCH 02/23] Update mac ports to 0.3.11 (#2020) --- mise.toml | 1 + scripts/macports/Portfile | 192 ++++++++++++++-------------- scripts/update-macports-portfile.py | 2 +- 3 files changed, 98 insertions(+), 97 deletions(-) diff --git a/mise.toml b/mise.toml index fcbe53b40..9f0fb2aa3 100644 --- a/mise.toml +++ b/mise.toml @@ -71,4 +71,5 @@ description = "Prepare for a release" run = """ git checkout -b bump uv run --group dev rooster release +prek run mdformat --files CHANGELOG.md """ diff --git a/scripts/macports/Portfile b/scripts/macports/Portfile index 0aa848416..6e431bbf6 100644 --- a/scripts/macports/Portfile +++ b/scripts/macports/Portfile @@ -4,11 +4,11 @@ PortSystem 1.0 PortGroup cargo 1.0 PortGroup github 1.0 -github.setup j178 prek 0.3.5 v +github.setup j178 prek 0.3.11 v github.tarball_from archive revision 0 -description A fast Git hook manager written in Rust, designed as a drop-in alternative to pre-commit, reimagined. +description A fast Git hook manager written in Rust, drop-in alternative to pre-commit. long_description {*}${description} categories devel @@ -18,9 +18,9 @@ maintainers {@j178 j178.dev:hi} openmaintainer homepage https://prek.j178.dev checksums ${distname}${extract.suffix} \ - rmd160 953c5729f50d8e57a4011fca43978abcc2308849 \ - sha256 3d0bf93af3591762b2fce97965fb88f8dc4b750164451162f57f866e26e4bb67 \ - size 524673 + rmd160 286d91969d00139c7886f2a5a4b4789494e638af \ + sha256 7480500dea21e8d457e5fa189ed9061fbb1219a897c28c66dc97e50afeef13f6 \ + size 681943 post-build { # Generate shell completions for supported shells @@ -55,25 +55,25 @@ cargo.crates \ ahash 0.8.12 5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75 \ aho-corasick 1.1.4 ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301 \ aligned-vec 0.6.4 dc890384c8602f339876ded803c97ad529f3842aba97f6392b3dba0dd171769b \ - annotate-snippets 0.12.12 c86cd1c51b95d71dde52bca69ed225008f6ff4c8cc825b08042aa1ef823e1980 \ - anstream 0.6.21 43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a \ - anstyle 1.0.13 5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78 \ - anstyle-parse 0.2.7 4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2 \ + annotate-snippets 0.12.15 92570a3f9c98e7e84df84b71d0965ac99b1871fcd75a3773a3bd1bad13f64cf7 \ + anstream 1.0.0 824a212faf96e9acacdbd09febd34438f8f711fb84e09a8916013cd7815ca28d \ + anstyle 1.0.14 940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000 \ + anstyle-parse 1.0.0 52ce7f38b242319f7cabaa6813055467063ecdc9d355bbb4ce0c68908cd8130e \ anstyle-query 1.1.5 40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc \ anstyle-wincon 3.0.11 291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d \ anyhow 1.0.102 7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c \ ar_archive_writer 0.5.1 7eb93bbb63b9c227414f6eb3a0adfddca591a8ce1e9b60661bb08969b87e340b \ arraydeque 0.5.1 7d902e3d592a523def97af8f317b08ce16b7ab854c1985a0c671e6f15cebc236 \ arrayvec 0.7.6 7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50 \ - assert_cmd 2.1.2 9c5bcfa8749ac45dd12cb11055aeeb6b27a3895560d60d71e3c23bf979e60514 \ + assert_cmd 2.2.1 39bae1d3fa576f7c6519514180a72559268dd7d1fe104070956cb687bc6673bd \ assert_fs 1.1.3 a652f6cb1f516886fcfee5e7a5c078b9ade62cfcb889524efe5a64d682dd27a9 \ - astral-tokio-tar 0.5.6 ec179a06c1769b1e42e1e2cbe74c7dcdb3d6383c838454d063eaac5bbb7ebbe5 \ + astral-tokio-tar 0.6.0 3c23f3af104b40a3430ccb90ed5f7bd877a8dc5c26fc92fde51a22b40890dcf9 \ astral_async_zip 0.0.17 ab72a761e6085828cc8f0e05ed332b2554701368c5dc54de551bfaec466518ba \ async-compression 0.4.41 d0f9ee0f6e02ffd7ad5816e9464499fba7b3effd01123b515c41d1697c43dad1 \ atomic-waker 1.1.2 1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0 \ autocfg 1.5.0 c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8 \ - aws-lc-rs 1.16.1 94bffc006df10ac2a68c83692d734a465f8ee6c5b384d8545a636f81d858f4bf \ - aws-lc-sys 0.38.0 4321e568ed89bb5a7d291a7f37997c2c0df89809d7b6d12062c81ddb54aa782e \ + aws-lc-rs 1.16.2 a054912289d18629dc78375ba2c3726a3afe3ff71b4edba9dedfca0e3446d1fc \ + aws-lc-sys 0.39.1 83a25cf98105baa966497416dbd42565ce3a8cf8dbfd59803ec9ad46f3126399 \ axoasset 2.0.1 1be1b9c2739b635e04c7bbcde9e89dd5e874b9e86e28f1b41c44eb830635d83e \ axoprocess 0.2.1 8a4b4798a6c02e91378537c63cd6e91726900b595450daa5d487bc3c11e95e1b \ axotag 0.3.0 dc923121fbc4cc72e9008436b5650b98e56f94b5799df59a1b4f572b5c6a7e6b \ @@ -93,23 +93,22 @@ cargo.crates \ camino 1.2.2 e629a66d692cb9ff1a1c664e41771b3dcaf961985a9774c0eb0bd1b51cf60a48 \ cargo-platform 0.3.2 87a0c0e6148f11f01f32650a2ea02d532b2ad4e81d8bd41e6e565b5adc5e6082 \ cargo_metadata 0.23.1 ef987d17b0a113becdd19d3d0022d04d7ef41f9efe4f3fb63ac44ba61df3ade9 \ - cc 1.2.56 aebf35691d1bfb0ac386a69bac2fde4dd276fb618cf8bf4f5318fe285e821bb2 \ + cc 1.2.59 b7a4d3ec6524d28a329fc53654bbadc9bdd7b0431f5d65f1a56ffb28a1ee5283 \ cesu8 1.1.0 6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c \ cfg-if 1.0.4 9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801 \ cfg_aliases 0.2.1 613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724 \ chacha20 0.10.0 6f8d983286843e49675a4b7a2d174efe136dc93a18d69130dd18198a6c167601 \ - clap 4.5.60 2797f34da339ce31042b27d23607e051786132987f595b02ba4f6a6dffb7030a \ - clap_builder 4.5.60 24a241312cea5059b13574bb9b3861cabf758b879c15190b37b6d6fd63ab6876 \ - clap_complete 4.5.66 c757a3b7e39161a4e56f9365141ada2a6c915a8622c408ab6bb4b5d047371031 \ - clap_derive 4.5.55 a92793da1a46a5f2a02a6f4c46c6496b28c43638adea8306fcb0caa1634f24e5 \ - clap_lex 1.0.0 3a822ea5bc7590f9d40f1ba12c0dc3c2760f3482c6984db1573ad11031420831 \ - cmake 0.1.57 75443c44cd6b379beb8c5b45d85d0773baf31cce901fe7bb252f4eff3008ef7d \ - colorchoice 1.0.4 b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75 \ + clap 4.6.1 1ddb117e43bbf7dacf0a4190fef4d345b9bad68dfc649cb349e7d17d28428e51 \ + clap_builder 4.6.0 714a53001bf66416adb0e2ef5ac857140e7dc3a0c48fb28b2f10762fc4b5069f \ + clap_complete 4.6.2 3ff7a1dccbdd8b078c2bdebff47e404615151534d5043da397ec50286816f9cb \ + clap_derive 4.6.1 f2ce8604710f6733aa641a2b3731eaa1e8b3d9973d5e3565da11800813f997a9 \ + clap_lex 1.1.0 c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9 \ + cmake 0.1.58 c0f78a02292a74a88ac736019ab962ece0bc380e3f977bf72e376c5d78ff0678 \ + colorchoice 1.0.5 1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570 \ combine 4.6.7 ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd \ compression-codecs 0.4.37 eb7b51a7d9c967fc26773061ba86150f19c50c0d65c887cb1fbe295fd16619b7 \ compression-core 0.4.31 75984efb6ed102a0d42db99afb6c1948f0380d1d91808d5529916e6c08b49d8d \ - console 0.15.11 054ccb5b10f9f2cbf51eb355ca1d05c2d279ce1804688d0db74b4733a5aeafd8 \ - console 0.16.2 03e45a4a8926227e4197636ba97a9fc9b00477e9f4bd711395687c5f0734bec4 \ + console 0.16.3 d64e8af5551369d19cf50138de61f1c42074ab970f74e99be916646777f8fc87 \ core-foundation 0.9.4 91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f \ core-foundation 0.10.1 b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6 \ core-foundation-sys 0.8.7 773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b \ @@ -132,14 +131,13 @@ cargo.crates \ encode_unicode 1.0.0 34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0 \ encoding_rs 0.8.35 75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3 \ encoding_rs_io 0.1.7 1cc3c5651fb62ab8aa3103998dade57efdd028544bd300516baa31840c252a83 \ - env_home 0.1.0 c7f84e12ccf0a7ddc17a6c41c93326024c42920d7ee630d04950e6926645c0fe \ equator 0.4.2 4711b213838dfee0117e3be6ac926007d7f433d7bbe33595975d4190cb07e6fc \ equator-macro 0.4.2 44f23cf4b44bfce11a86ace86f8a73ffdec849c9fd00a386a53d278bd9e81fb3 \ equivalent 1.0.2 877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f \ errno 0.3.14 39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb \ etcetera 0.11.0 de48cc4d1c1d97a20fd819def54b890cadde72ed3ad0c614822a0a433361be96 \ fancy-regex 0.17.0 72cf461f865c862bb7dc573f643dd6a2b6842f7c30b07882b56bd148cc2761b8 \ - fastrand 2.3.0 37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be \ + fastrand 2.4.0 a043dc74da1e37d6afe657061213aa6f425f855399a11d3463c6ecccc4dfda1f \ filetime 0.2.27 f98844151eee8917efc50bd9e8318cb963ae8b297431495d3f758616ea5c57db \ find-msvc-tools 0.1.9 5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582 \ findshlibs 0.10.2 40b9e59cd0f7e0806cca4be089683ecb6434e602038df21fe6bf6711b2f07f64 \ @@ -178,50 +176,52 @@ cargo.crates \ http-body 1.0.1 1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184 \ http-body-util 0.1.3 b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a \ httparse 1.10.1 6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87 \ - hyper 1.8.1 2ab2d4f250c3d7b1c9fcdff1cece94ea4e2dfbec68614f7b87cb205f24ca9d11 \ + hyper 1.9.0 6299f016b246a94207e63da54dbe807655bf9e00044f73ded42c3ac5305fbcca \ hyper-rustls 0.27.7 e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58 \ hyper-util 0.1.20 96547c2556ec9d12fb1578c4eaf448b04993e7fb79cbaad930a656880a6bdfa0 \ - icu_collections 2.1.1 4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43 \ - icu_locale_core 2.1.1 edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6 \ - icu_normalizer 2.1.1 5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599 \ - icu_normalizer_data 2.1.1 7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a \ - icu_properties 2.1.2 020bfc02fe870ec3a66d93e677ccca0562506e5872c650f893269e08615d74ec \ - icu_properties_data 2.1.2 616c294cf8d725c6afcd8f55abc17c56464ef6211f9ed59cccffe534129c77af \ - icu_provider 2.1.1 85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614 \ + icu_collections 2.2.0 2984d1cd16c883d7935b9e07e44071dca8d917fd52ecc02c04d5fa0b5a3f191c \ + icu_locale_core 2.2.0 92219b62b3e2b4d88ac5119f8904c10f8f61bf7e95b640d25ba3075e6cac2c29 \ + icu_normalizer 2.2.0 c56e5ee99d6e3d33bd91c5d85458b6005a22140021cc324cea84dd0e72cff3b4 \ + icu_normalizer_data 2.2.0 da3be0ae77ea334f4da67c12f149704f19f81d1adf7c51cf482943e84a2bad38 \ + icu_properties 2.2.0 bee3b67d0ea5c2cca5003417989af8996f8604e34fb9ddf96208a033901e70de \ + icu_properties_data 2.2.0 8e2bbb201e0c04f7b4b3e14382af113e17ba4f63e2c9d2ee626b720cbce54a14 \ + icu_provider 2.2.0 139c4cf31c8b5f33d7e199446eff9c1e02decfc2f0eec2c8d71f65befa45b421 \ id-arena 2.3.0 3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954 \ idna 1.1.0 3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de \ idna_adapter 1.2.1 3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344 \ ignore 0.4.25 d3d782a365a015e0f5c04902246139249abf769125006fbe7649e2ee88169b4a \ - image 0.25.9 e6506c6c10786659413faa717ceebcb8f70731c0a60cbae39795fdf114519c1a \ - indexmap 2.13.0 7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017 \ + image 0.25.10 85ab80394333c02fe689eaf900ab500fbd0c2213da414687ebf995a65d5a6104 \ + indexmap 2.13.1 45a8a2b9cb3e0b0c1803dbb0758ffac5de2f425b23c28f518faabd9d805342ff \ indicatif 0.18.4 25470f23803092da7d239834776d653104d551bc4d7eacaf31e6837854b8e9eb \ indoc 2.0.7 79cf5c93f93228cf8efb3ba362535fb11199ac548a09ce117c9b1adc3030d706 \ inferno 0.11.21 232929e1d75fe899576a3d5c7416ad0d88dbfbb3c3d6aa00873a7408a50ddb88 \ - insta 1.46.3 e82db8c87c7f1ccecb34ce0c24399b8a73081427f3c7c50a5d597925356115e4 \ + insta 1.47.2 7b4a6248eb93a4401ed2f37dfe8ea592d3cf05b7cf4f8efa867b6895af7e094e \ insta-cmd 0.6.0 ffeeefa927925cced49ccb01bf3e57c9d4cd132df21e576eb9415baeab2d3de6 \ ipnet 2.12.0 d98f6fed1fde3f8c21bc40a1abb88dd75e67924f9cffc3ef95607bad8017f8e2 \ - iri-string 0.7.10 c91338f0783edbd6195decb37bae672fd3b165faffb89bf7b9e6942f8b1a731a \ + iri-string 0.7.12 25e659a4bb38e810ebc252e53b5814ff908a8c58c2a9ce2fae1bbec24cbf4e20 \ is-terminal 0.4.17 3640c1c38b8e4e43584d8df18be5fc6b0aa314ce6ebf51b53313d4306cca8e46 \ is_executable 1.0.5 baabb8b4867b26294d818bf3f651a454b6901431711abb96e296245888d6e8c4 \ is_terminal_polyfill 1.70.2 a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695 \ itertools 0.14.0 2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285 \ - itoa 1.0.17 92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2 \ + itoa 1.0.18 8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682 \ jni 0.21.1 1a87aa2bb7d2af34197c04845522473242e1aa17c12f4935d5856491a7fb8c97 \ - jni-sys 0.3.0 8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130 \ + jni-sys 0.3.1 41a652e1f9b6e0275df1f15b32661cf0d4b78d4d87ddec5e0c3c20f097433258 \ + jni-sys 0.4.1 c6377a88cb3910bee9b0fa88d4f42e1d2da8e79915598f65fb0c7ee14c878af2 \ + jni-sys-macros 0.4.1 38c0b942f458fe50cdac086d2f946512305e5631e720728f2a61aabcd47a6264 \ jobserver 0.1.34 9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33 \ - js-sys 0.3.91 b49715b7073f385ba4bc528e5747d02e66cb39c6146efb66b781f131f0fb399c \ + js-sys 0.3.94 2e04e2ef80ce82e13552136fabeef8a5ed1f985a96805761cbb9a2c34e7664d9 \ json5 1.3.1 733a844dbd6fef128e98cb4487b887cb55454d92cd9994b1bafe004fabbe670c \ lazy-regex 3.6.0 6bae91019476d3ec7147de9aa291cadb6d870abf2f3015d2da73a90325ac1496 \ lazy-regex-proc_macros 3.6.0 4de9c1e1439d8b7b3061b2d209809f447ca33241733d9a3c01eabf2dc8d94358 \ lazy_static 1.5.0 bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe \ leb128fmt 0.1.0 09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2 \ levenshtein 1.0.5 db13adb97ab515a3691f56e4dbab09283d0b86cb45abd991d8634a9d6f501760 \ - libc 0.2.182 6800badb6cb2082ffd7b6a67e6125bb39f18782f793520caee8cb8846be06112 \ + libc 0.2.185 52ff2c0fe9bc6cb6b14a0592c2ff4fa9ceb83eea9db979b0487cd054946a2b8f \ liblzma 0.4.6 b6033b77c21d1f56deeae8014eb9fbe7bdf1765185a6c508b5ca82eeaed7f899 \ - liblzma-sys 0.4.5 9f2db66f3268487b5033077f266da6777d057949b8f93c8ad82e441df25e6186 \ - libredox 0.1.14 1744e39d1d6a9948f4f388969627434e31128196de472883b39f148769bfe30a \ + liblzma-sys 0.4.6 1a60851d15cd8c5346eca4ab8babff585be2ae4bc8097c067291d3ffe2add3b6 \ + libredox 0.1.15 7ddbf48fd451246b1f8c2610bd3b4ac0cc6e149d89832867093ab69a17194f08 \ linux-raw-sys 0.12.1 32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53 \ - litemap 0.8.1 6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77 \ + litemap 0.8.2 92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0 \ lock_api 0.4.14 224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965 \ log 0.4.29 5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897 \ lru-slab 0.1.2 112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154 \ @@ -234,8 +234,8 @@ cargo.crates \ miette-derive 7.6.0 db5b29714e950dbb20d5e6f74f9dcec4edbcc1067bb7f8ed198c097b8c1a818b \ mime 0.3.17 6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a \ miniz_oxide 0.8.9 1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316 \ - mio 1.1.1 a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc \ - moxcms 0.7.11 ac9557c559cd6fc9867e122e20d2cbefc9ca29d80d027a8e39310920ed2f0a97 \ + mio 1.2.0 50b7e5b27aa02a74bac8c3f23f448f8d87ff11f92d3aac1a6ed369ee08cc56c1 \ + moxcms 0.8.1 bb85c154ba489f01b25c0d36ae69a87e4a1c73a72631fc6c0eb6dde34a73e44b \ nix 0.26.4 598beaf3cc6fdd9a5dfb1630c2800c7acd31df7aaf0f565796fba2b53ca1af1b \ nix 0.30.1 74523f3a35e05aba87a1d978330aef40f67b0304ac79c1c00b294c9830543db6 \ nix 0.31.2 5d6d0705320c1e6ba1d912b5e37cf18071b6c2e9b7fa8215a1e8a7651966f5d3 \ @@ -247,7 +247,7 @@ cargo.crates \ objc2 0.6.4 3a12a8ed07aefc768292f076dc3ac8c48f3781c8f2d5851dd3d98950e8c5a89f \ objc2-encode 4.1.0 ef25abbcd74fb2609453eb695bd2f860d389e457f67dc17cafc8b8cbc89d0c33 \ object 0.37.3 ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe \ - once_cell 1.21.3 42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d \ + once_cell 1.21.4 9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50 \ once_cell_polyfill 1.70.2 384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe \ openssl-probe 0.2.1 7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe \ owo-colors 4.3.0 d211803b9b6b570f68772237e415a029d5a50c65d382910b879fb19d3271f94d \ @@ -261,11 +261,10 @@ cargo.crates \ pin-project 1.1.11 f1749c7ed4bcaf4c3d0a3efc28538844fb29bcdd7d2b67b2be7e20ba861ff517 \ pin-project-internal 1.1.11 d9b20ed30f105399776b9c883e68e536ef602a16ae6f596d2c473591d6ad64c6 \ pin-project-lite 0.2.17 a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd \ - pin-utils 0.1.0 8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184 \ pkg-config 0.3.32 7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c \ plain 0.2.3 b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6 \ portable-atomic 1.13.1 c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49 \ - potential_utf 0.1.4 b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77 \ + potential_utf 0.1.5 0103b1cef7ec0cf76490e969665504990193874ea05c85ff9bab8b911d0a0564 \ pprof 0.15.0 38a01da47675efa7673b032bf8efd8214f1917d89685e07e395ab125ea42b187 \ ppv-lite86 0.2.21 85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9 \ predicates 3.1.4 ada8f2932f28a27ee7b70dd6c1c39ea0675c55a36879ab92f3a715eaa1e63cfe \ @@ -279,17 +278,17 @@ cargo.crates \ quick-xml 0.26.0 7f50b1c63b38611e7d4d7f68b82d3ad0cc71a2ad2e7f61fc10f1328d917c93cd \ quick-xml 0.39.2 958f21e8e7ceb5a1aa7fa87fab28e7c75976e0bfe7e23ff069e0a260f894067d \ quinn 0.11.9 b9e20a958963c291dc322d98411f541009df2ced7b5a4f2bd52337638cfccf20 \ - quinn-proto 0.11.13 f1906b49b0c3bc04b5fe5d86a77925ae6524a19b816ae38ce1e426255f1d8a31 \ + quinn-proto 0.11.14 434b42fec591c96ef50e21e886936e66d3cc3f737104fdb9b737c40ffb94c098 \ quinn-udp 0.5.14 addec6a0dcad8a8d96a771f815f0eaf55f9d1805756410b39f5fa81332574cbd \ quote 1.0.45 41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924 \ r-efi 5.3.0 69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f \ r-efi 6.0.0 f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf \ rand 0.9.2 6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1 \ - rand 0.10.0 bc266eb313df6c5c09c1c7b1fbe2510961e5bcd3add930c1e31f7ed9da0feff8 \ + rand 0.10.1 d2e8e8bcc7961af1fdac401278c6a831614941f6164ee3bf4ce61b7edb162207 \ rand_chacha 0.9.0 d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb \ rand_core 0.9.5 76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c \ rand_core 0.10.0 0c8d0fd677905edcbeedbf2edb6494d676f0e98d54d5cf9bda0b061cb8fb8aba \ - rayon 1.11.0 368f01d005bf8fd9b1206fb6fa653e6c4a81ceb1466406b81792d87c5677a58f \ + rayon 1.12.0 fb39b166781f92d482534ef4b4b1b2568f42613b53e5b6c160e24cfbfa30926d \ rayon-core 1.13.0 22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91 \ redox_syscall 0.7.3 6ce70a74e890531977d37e532c34d45e9055d2409ed08ddba14529471ed0be16 \ ref-cast 1.0.25 f354300ae66f76f1c85c5f84693f0ce81d747e2c3f21a45fef496d89c960bf7d \ @@ -301,43 +300,45 @@ cargo.crates \ rgb 0.8.53 47b34b781b31e5d73e9fbc8689c70551fd1ade9a19e3e28cfec8580a79290cc4 \ ring 0.17.14 a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7 \ rustc-demangle 0.1.27 b50b8869d9fc858ce7266cce0194bd74df58b9d0e3f6df3a9fc8eb470d95c09d \ - rustc-hash 2.1.1 357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d \ + rustc-hash 2.1.2 94300abf3f1ae2e2b8ffb7b58043de3d399c73fa6f4b73826402a5c457614dbe \ rustix 1.1.4 b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190 \ rustls 0.23.37 758025cb5fccfd3bc2fd74708fd4682be41d99e5dff73c377c0646c6012c73a4 \ rustls-native-certs 0.8.3 612460d5f7bea540c490b2b6395d8e34a953e52b491accd6c86c8164c5932a63 \ rustls-pki-types 1.14.0 be040f8b0a225e40375822a563fa9524378b9d63112f53e19ffff34df5d33fdd \ rustls-platform-verifier 0.6.2 1d99feebc72bae7ab76ba994bb5e121b8d83d910ca40b36e0921f53becc41784 \ rustls-platform-verifier-android 0.1.1 f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f \ - rustls-webpki 0.103.9 d7df23109aa6c1567d1c575b9952556388da57401e4ace1d15f79eedad0d8f53 \ + rustls-webpki 0.103.13 61c429a8649f110dddef65e2a5ad240f747e85f7758a6bccc7e5777bd33f756e \ rustversion 1.0.22 b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d \ same-file 1.0.6 93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502 \ - saphyr-parser-bw 0.0.608 d55ae5ea09894b6d5382621db78f586df37ef18ab581bf32c754e75076b124b1 \ - schannel 0.1.28 891d81b926048e76efe18581bf793546b4c0eaf8448d72be8de2bbee5fd166e1 \ + saphyr-parser-bw 0.0.611 67dec0c833db75dc98957956b303fe447ffc5eb13f2325ef4c2350f7f3aa69e3 \ + schannel 0.1.29 91c1b7e4904c873ef0710c1f407dde2e6287de2bebc1bbbf7d430bb7cbffd939 \ schemars 1.2.1 a2b42f36aa1cd011945615b92222f6bf73c599a102a300334cd7f8dbeec726cc \ schemars_derive 1.2.1 7d115b50f4aaeea07e79c1912f645c7513d81715d0420f8bc77a18c6260b307f \ scopeguard 1.2.0 94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49 \ + seahash 4.1.0 1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b \ security-framework 3.7.0 b7f4bc775c73d9a02cde8bf7b2ec4c9d12743edf609006c7facc23998404cd1d \ security-framework-sys 2.17.0 6ce2691df843ecc5d231c0b14ece2acc3efb62c0a398c7e1d875f3983ce020e3 \ self-replace 1.5.0 03ec815b5eab420ab893f63393878d89c90fdd94c0bcc44c07abb8ad95552fb7 \ - semver 1.0.27 d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2 \ + semver 1.0.28 8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd \ serde 1.0.228 9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e \ - serde-saphyr 0.0.20 bfcaa44cda9e21eaf5fefc86175d544a359d4de9bcd1f3a90be7bbf77dfc3492 \ + serde-saphyr 0.0.23 09fbdfe7a27a1b1633dfc0c4c8e65940b8d819c5ddb9cca48ebc3223b00c8b14 \ serde_core 1.0.228 41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad \ serde_derive 1.0.228 d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79 \ serde_derive_internals 0.29.1 18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711 \ serde_json 1.0.149 83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86 \ - serde_spanned 1.0.4 f8bbf91e5a4d6315eee45e704372590b30e260ee83af6639d64557f51b067776 \ + serde_spanned 1.1.1 6662b5879511e06e8999a8a235d848113e942c9124f211511b16466ee2995f26 \ serde_stacker 0.1.14 d4936375d50c4be7eff22293a9344f8e46f323ed2b3c243e52f89138d9bb0f4a \ sharded-slab 0.1.7 f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6 \ shlex 1.3.0 0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64 \ signal-hook-registry 1.4.8 c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b \ - simd-adler32 0.3.8 e320a6c5ad31d271ad523dcf3ad13e2767ad8b1cb8f047f75a8aeaf8da139da2 \ + simd-adler32 0.3.9 703d5c7ef118737c72f1af64ad2f6f8c5e1921f818cdcb97b8fe6fc69bf66214 \ similar 2.7.0 bbbb5d9659141646ae647b42fe094daf6c6192d1620870b449d9557f748b2daa \ + similar 3.1.0 04d93e861ede2e497b47833469b8ec9d5c07fa4c78ce7a00f6eb7dd8168b4b3f \ siphasher 1.0.2 b2aa850e253778c88a04c3d7323b043aeda9d3e30d5971937c1855769763678e \ slab 0.4.12 0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5 \ smallvec 1.15.1 67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03 \ smawk 0.3.2 b7c388c1b5e93756d0c740965c41e8822f866621d41acbdf6336a6a168f8840c \ - socket2 0.6.2 86f4aa3ad99f2088c990dfa82d367e19cb29268ed67c574d10d0a4bfe71f07e0 \ + socket2 0.6.3 3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e \ spin 0.10.0 d5fe4ccb98d9c292d56fec89a5e07da7fc4cf0dc11e156b41793132775d3e591 \ stable_deref_trait 1.2.1 6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596 \ stacker 0.1.23 08d74a23609d509411d10e2176dc2a4346e3b4aea2e7b1869f19fdedbc71c013 \ @@ -346,16 +347,16 @@ cargo.crates \ strum 0.28.0 9628de9b8791db39ceda2b119bbe13134770b56c138ec1d3af810d045c04f9bd \ strum_macros 0.28.0 ab85eea0270ee17587ed4156089e10b9e6880ee688791d45a905f5b1ca36f664 \ subtle 2.6.1 13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292 \ - symbolic-common 12.17.2 751a2823d606b5d0a7616499e4130a516ebd01a44f39811be2b9600936509c23 \ - symbolic-demangle 12.17.2 79b237cfbe320601dd24b4ac817a5b68bb28f5508e33f08d42be0682cadc8ac9 \ + symbolic-common 12.17.3 52ca086c1eb5c7ee74b151ba83c6487d5d33f8c08ad991b86f3f58f6629e68d5 \ + symbolic-demangle 12.17.3 baa911a28a62823aaf2cc2e074212492a3ee69d0d926cc8f5b12b4a108ff5c0c \ syn 2.0.117 e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99 \ sync_wrapper 1.0.2 0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263 \ synstructure 0.13.2 728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2 \ system-configuration 0.7.0 a13f3d0daba03132c0aa9767f98351b3488edc2c100cda2d2ec2b04f3d8d3c8b \ system-configuration-sys 0.6.0 8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4 \ target-lexicon 0.13.5 adb6935a6f5c20170eeceb1a3835a49e12e19d792f6dd344ccc76a985ca5a6ca \ - tempfile 3.26.0 82a72c767771b47409d2345987fda8628641887d5466101319899796367354a0 \ - terminal_size 0.4.3 60b8cb979cb11c32ce1603f8137b22262a9d131aaa5c37b5678025f22b8becd0 \ + tempfile 3.27.0 32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd \ + terminal_size 0.4.4 230a1b821ccbd75b185820a1f1ff7b14d21da1e442e22c0863ea5f08771a8874 \ termtree 0.5.1 8f50febec83f5ee1df3015341d8bd429f2d1cc62bcba7ea2076759d315084683 \ textwrap 0.16.2 c13547615a44dc9c452a8a534638acdf07120d4b6847c8178705da06306a3057 \ thiserror 1.0.69 b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52 \ @@ -363,19 +364,19 @@ cargo.crates \ thiserror-impl 1.0.69 4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1 \ thiserror-impl 2.0.18 ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5 \ thread_local 1.1.9 f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185 \ - tinystr 0.8.2 42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869 \ - tinyvec 1.10.0 bfa5fdc3bce6191a1dbc8c02d5c8bffcf557bafa17c124c5264a458f1b0613fa \ + tinystr 0.8.3 c8323304221c2a851516f22236c5722a72eaa19749016521d6dff0824447d96d \ + tinyvec 1.11.0 3e61e67053d25a4e82c844e8424039d9745781b3fc4f32b8d55ed50f5f667ef3 \ tinyvec_macros 0.1.1 1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20 \ - tokio 1.50.0 27ad5e34374e03cfffefc301becb44e9dc3c17584f414349ebe29ed26661822d \ - tokio-macros 2.6.1 5c55a2eff8b69ce66c84f85e1da1c233edc36ceb85a2058d11b0d6a3c7e7569c \ + tokio 1.52.1 b67dee974fe86fd92cc45b7a95fdd2f99a36a6d7b0d431a231178d3d670bbcc6 \ + tokio-macros 2.7.0 385a6cb71ab9ab790c5fe8d67f1645e6c450a7ce006a33de03daa956cf70a496 \ tokio-rustls 0.26.4 1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61 \ tokio-stream 0.1.18 32da49809aab5c3bc678af03902d4ccddea2a87d028d86392a4b1560c6906c70 \ tokio-util 0.7.18 9ae9cec805b01e8fc3fd2fe289f89149a9b66dd16786abd8b19cfa7b48cb0098 \ - toml 1.0.3+spec-1.1.0 c7614eaf19ad818347db24addfa201729cf2a9b6fdfd9eb0ab870fcacc606c0c \ - toml_datetime 1.0.0+spec-1.1.0 32c2555c699578a4f59f0cc68e5116c8d7cabbd45e1409b989d4be085b53f13e \ - toml_edit 0.25.3+spec-1.1.0 a0a07913e63758bc95142d9863a5a45173b71515e68b690cad70cf99c3255ce1 \ - toml_parser 1.0.9+spec-1.1.0 702d4415e08923e7e1ef96cd5727c0dfed80b4d2fa25db9647fe5eb6f7c5a4c4 \ - toml_writer 1.0.6+spec-1.1.0 ab16f14aed21ee8bfd8ec22513f7287cd4a91aa92e44edfe2c17ddd004e92607 \ + toml 1.1.2+spec-1.1.0 81f3d15e84cbcd896376e6730314d59fb5a87f31e4b038454184435cd57defee \ + toml_datetime 1.1.1+spec-1.1.0 3165f65f62e28e0115a00b2ebdd37eb6f3b641855f9d636d3cd4103767159ad7 \ + toml_edit 0.25.11+spec-1.1.0 0b59c4d22ed448339746c59b905d24568fcbb3ab65a500494f7b8c3e97739f2b \ + toml_parser 1.1.2+spec-1.1.0 a2abe9b86193656635d2411dc43050282ca48aa31c2451210f4202550afb7526 \ + toml_writer 1.1.1+spec-1.1.0 756daf9b1013ebe47a8776667b466417e2d4c5679d441c26230efd9ef78692db \ tower 0.5.3 ebe5ef63511595f1344e2d5cfa636d973292adc0eec1f0ad45fae9f0851ab1d4 \ tower-http 0.6.8 d4e6559d53cc268e5031cd8429d05415bc4cb4aefc4aa5d6cc35fbf5b924a1f8 \ tower-layer 0.3.3 121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e \ @@ -384,7 +385,7 @@ cargo.crates \ tracing-attributes 0.1.31 7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da \ tracing-core 0.1.36 db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a \ tracing-log 0.2.0 ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3 \ - tracing-subscriber 0.3.22 2f30143827ddab0d256fd843b7a66d164e9f271cfa0dde49142c5ca0ca291f1e \ + tracing-subscriber 0.3.23 cb7f578e5945fb242538965c2d0b04418d38ec25c79d160cd279bf0731c8d319 \ try-lock 0.2.5 e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b \ ucd-trie 0.1.7 2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971 \ unicode-id 0.3.6 70ba288e709927c043cbe476718d37be306be53fb1fafecd0dbe36d072be2580 \ @@ -398,7 +399,7 @@ cargo.crates \ url 2.5.8 ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed \ utf8_iter 1.0.4 b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be \ utf8parse 0.2.2 06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821 \ - uuid 1.21.0 b672338555252d43fd2240c714dc444b8c6fb0a5c5335e65a07bba7742735ddb \ + uuid 1.23.0 5ac8b6f42ead25368cf5b098aeb3dc8a1a2c05a3eee8a9a1a68c640edbfc79d9 \ valuable 0.1.1 ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65 \ version_check 0.9.5 0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a \ wait-timeout 0.2.1 09ac3b126d3914f9849036f826e054cbabdc8519970b8998ddaf3b5bd3c65f11 \ @@ -407,19 +408,19 @@ cargo.crates \ wasi 0.11.1+wasi-snapshot-preview1 ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b \ wasip2 1.0.2+wasi-0.2.9 9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5 \ wasip3 0.4.0+wasi-0.3.0-rc-2026-01-06 5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5 \ - wasm-bindgen 0.2.114 6532f9a5c1ece3798cb1c2cfdba640b9b3ba884f5db45973a6f442510a87d38e \ - wasm-bindgen-futures 0.4.64 e9c5522b3a28661442748e09d40924dfb9ca614b21c00d3fd135720e48b67db8 \ - wasm-bindgen-macro 0.2.114 18a2d50fcf105fb33bb15f00e7a77b772945a2ee45dcf454961fd843e74c18e6 \ - wasm-bindgen-macro-support 0.2.114 03ce4caeaac547cdf713d280eda22a730824dd11e6b8c3ca9e42247b25c631e3 \ - wasm-bindgen-shared 0.2.114 75a326b8c223ee17883a4251907455a2431acc2791c98c26279376490c378c16 \ + wasm-bindgen 0.2.117 0551fc1bb415591e3372d0bc4780db7e587d84e2a7e79da121051c5c4b89d0b0 \ + wasm-bindgen-futures 0.4.67 03623de6905b7206edd0a75f69f747f134b7f0a2323392d664448bf2d3c5d87e \ + wasm-bindgen-macro 0.2.117 7fbdf9a35adf44786aecd5ff89b4563a90325f9da0923236f6104e603c7e86be \ + wasm-bindgen-macro-support 0.2.117 dca9693ef2bab6d4e6707234500350d8dad079eb508dca05530c85dc3a529ff2 \ + wasm-bindgen-shared 0.2.117 39129a682a6d2d841b6c429d0c51e5cb0ed1a03829d8b3d1e69a011e62cb3d3b \ wasm-encoder 0.244.0 990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319 \ wasm-metadata 0.244.0 bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909 \ wasm-streams 0.5.0 9d1ec4f6517c9e11ae630e200b2b65d193279042e28edd4a2cda233e46670bbb \ wasmparser 0.244.0 47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe \ - web-sys 0.3.91 854ba17bb104abfb26ba36da9729addc7ce7f06f5c0f90f3c391f8461cca21f9 \ + web-sys 0.3.94 cd70027e39b12f0849461e08ffc50b9cd7688d942c1c8e3c7b22273236b4dd0a \ web-time 1.1.0 5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb \ - webpki-root-certs 1.0.6 804f18a4ac2676ffb4e8b5b5fa9ae38af06df08162314f96a68d2a363e21a8ca \ - which 8.0.0 d3fabb953106c3c8eea8306e4393700d7657561cb43122571b172bbfb7c7ba1d \ + webpki-root-certs 1.0.7 f31141ce3fc3e300ae89b78c0dd67f9708061d1d2eda54b8209346fd6be9a92c \ + which 8.0.2 81995fafaaaf6ae47a7d0cc83c67caf92aeb7e5331650ae6ff856f7c0c60c459 \ widestring 1.2.1 72069c3113ab32ab29e5584db3c6ec55d416895e60715417b5b883a357c3e471 \ winapi 0.3.9 5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419 \ winapi-i686-pc-windows-gnu 0.4.0 ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6 \ @@ -471,25 +472,24 @@ cargo.crates \ windows_x86_64_msvc 0.42.2 9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0 \ windows_x86_64_msvc 0.52.6 589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec \ windows_x86_64_msvc 0.53.1 d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650 \ - winnow 0.7.14 5a5364e9d77fcdeeaa6062ced926ee3381faa2ee02d3eb83a5c27a8825540829 \ - winsafe 0.0.19 d135d17ab770252ad95e9a872d365cf3090e3be864a34ab46f48555993efc904 \ + winnow 1.0.1 09dac053f1cd375980747450bfc7250c264eaae0583872e845c0c7cd578872b5 \ wit-bindgen 0.51.0 d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5 \ wit-bindgen-core 0.51.0 ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc \ wit-bindgen-rust 0.51.0 b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21 \ wit-bindgen-rust-macro 0.51.0 0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a \ wit-component 0.244.0 9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2 \ wit-parser 0.244.0 ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736 \ - writeable 0.6.2 9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9 \ + writeable 0.6.3 1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4 \ xattr 1.6.1 32e45ad4206f6d2479085147f02bc2ef834ac85886624a23575ae137c8aa8156 \ yansi 1.0.1 cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049 \ - yoke 0.8.1 72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954 \ - yoke-derive 0.8.1 b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d \ - zerocopy 0.8.40 a789c6e490b576db9f7e6b6d661bcc9799f7c0ac8352f56ea20193b2681532e5 \ - zerocopy-derive 0.8.40 f65c489a7071a749c849713807783f70672b28094011623e200cb86dcb835953 \ - zerofrom 0.1.6 50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5 \ - zerofrom-derive 0.1.6 d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502 \ + yoke 0.8.2 abe8c5fda708d9ca3df187cae8bfb9ceda00dd96231bed36e445a1a48e66f9ca \ + yoke-derive 0.8.2 de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e \ + zerocopy 0.8.48 eed437bf9d6692032087e337407a86f04cd8d6a16a37199ed57949d415bd68e9 \ + zerocopy-derive 0.8.48 70e3cd084b1788766f53af483dd21f93881ff30d7320490ec3ef7526d203bad4 \ + zerofrom 0.1.7 69faa1f2a1ea75661980b013019ed6687ed0e83d069bc1114e2cc74c6c04c4df \ + zerofrom-derive 0.1.7 11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1 \ zeroize 1.8.2 b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0 \ - zerotrie 0.2.3 2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851 \ - zerovec 0.11.5 6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002 \ - zerovec-derive 0.11.2 eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3 \ + zerotrie 0.2.4 0f9152d31db0792fa83f70fb2f83148effb5c1f5b8c7686c3459e361d9bc20bf \ + zerovec 0.11.6 90f911cbc359ab6af17377d242225f4d75119aec87ea711a880987b18cd7b239 \ + zerovec-derive 0.11.3 625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555 \ zmij 1.0.21 b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa diff --git a/scripts/update-macports-portfile.py b/scripts/update-macports-portfile.py index 468190707..89f91cb19 100644 --- a/scripts/update-macports-portfile.py +++ b/scripts/update-macports-portfile.py @@ -155,7 +155,7 @@ def main() -> None: portfile.write_text(text, encoding="utf-8") print(f"Updated {portfile} for version {version}") print("To open a PR with the updated Portfile, run:") - print(f" git clone --depth=1 --branch=main https://github.com/macports/macports-ports.git /tmp/macports-ports") + print(f" git clone --depth=1 --branch=master https://github.com/macports/macports-ports.git /tmp/macports-ports") print(f" cp {portfile} /tmp/macports-ports/devel/prek/Portfile") print(f" cd /tmp/macports-ports") print(f" git add devel/prek/Portfile") From 3268a83577afdcf7115680ed92692c70753a0c06 Mon Sep 17 00:00:00 2001 From: Xiaoyan Li <58494362+xiaoyanli-lyft@users.noreply.github.com> Date: Mon, 27 Apr 2026 20:26:42 -0700 Subject: [PATCH 03/23] ruby: put resolved Ruby's bin dir on `$PATH` for `gem` invocations (#2021) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ### Summary `build_gemspec`, `resolve_gems`, `install_single_gem`, and `install_gems_sequential` in `crates/prek/src/languages/ruby/gem.rs` all spawn ` -S gem ...`. Ruby's `-S` flag searches `$PATH` for the named script. The rv-ruby tarballs that prek auto-downloads ship `gem` next to `ruby` in the same `bin/` directory, but prek wasn't putting that directory on `$PATH` for these child commands. In environments without a system Ruby on `PATH` (e.g. a vanilla Docker image / CI container), the `-S` lookup fails and Ruby aborts with: ``` //tools/ruby//bin/ruby: No such file or directory -- gem (LoadError) ``` The first place this trips is `build_gemspec` (called from `Ruby::install` before `install_gems`), so the user-visible failure is `Failed to install hook ...: Failed to build gemspecs`. Once that's worked around, `gem install --explain` would fail identically — same root cause for all four call sites. This is distinct from #2006 / #2017, which fixed missing `gems/bin/ruby` shim used at hook **run** time. The bug here is at hook **install** time and is not mitigated by 0.3.11 (`gem.rs` is unchanged across v0.3.10..v0.3.11). Reproduction repo / context: filed as a separate issue with the full repro alongside this PR. ### Fix Prepend the resolved Ruby's bin dir to `$PATH` for every `ruby -S gem` invocation: - New `ruby_path_env(&RubyResult) -> Result` helper that uses `prek_consts::prepend_paths` (same helper used by `Ruby::run`). - `gem_env` now takes `&RubyResult` in addition to `gem_home` and sets `PATH` alongside the existing `GEM_HOME` / `BUNDLE_*` / `MAKEFLAGS` env. Returns `Result` so the `prepend_paths` join error can propagate (vanishingly rare in practice). - `build_gemspec` doesn't have a `GEM_HOME` to set so it doesn't use `gem_env`, but it sets `PATH` directly via the same helper. ### Test plan - `cargo fmt --check -p prek` — clean - `cargo clippy -p prek --all-targets -- -D warnings` — clean - `cargo test -p prek --bin prek` — 400 passed; 0 failed (existing unit tests, including all five `languages::ruby::gem::tests::*`) - New integration test: `languages::ruby::auto_download_gem_install_without_gem_on_path` (CI-only, mirrors the existing `auto_download` gating). It: - pins `language_version: '3.2.9'` to force prek to auto-download Ruby via rv-ruby (and asserts a `tools/ruby/3.2.9*` directory exists after the run); - drops a `.gemspec` into the local repo so `build_gemspec` runs; - sets `additional_dependencies: ["webrick"]` so `resolve_gems` (`gem install --explain`) and `install_single_gem` (`gem install`) run; - scrubs `ruby` and `gem` from `$PATH` via the existing `remove_bin_from_path` helper, so `ruby -S gem ...` only resolves if the resolved Ruby's bin dir is prepended (i.e. the test would have failed before this fix with the `LoadError` quoted above). The pre-existing `auto_download` test only ran `ruby --version` and never hit `gem`; `gemspec_workflow` used `language_version: system` and so picked `gem` up from the system `PATH`. The new test combines auto-download + gem operations + scrubbed `PATH` to lock the regression in. ### Manual verification of the failure mode (without this fix) In a container with no system Ruby: ```yaml default_language_version: ruby: 3.2.1 repos: - repo: https://github.com/jumanjihouse/pre-commit-hooks rev: 3.0.0 hooks: - id: rubocop ``` ```sh prek install-hooks # error: Failed to install hook `rubocop` # caused by: Failed to build gemspecs # caused by: Command `gem build` exited with an error: # /.../tools/ruby/3.2.1/bin/ruby: No such file or directory -- gem (LoadError) ``` With this patch, prek prepends `/bin` to `$PATH`, `ruby -S gem` resolves, and the install proceeds. --------- Co-authored-by: Jo <10510431+j178@users.noreply.github.com> --- crates/prek/src/languages/ruby/gem.rs | 36 +++++++++++++++++++++------ 1 file changed, 29 insertions(+), 7 deletions(-) diff --git a/crates/prek/src/languages/ruby/gem.rs b/crates/prek/src/languages/ruby/gem.rs index 9729477dc..ba3e7028e 100644 --- a/crates/prek/src/languages/ruby/gem.rs +++ b/crates/prek/src/languages/ruby/gem.rs @@ -1,10 +1,11 @@ -use std::ffi::OsStr; +use std::ffi::{OsStr, OsString}; use std::path::{Path, PathBuf}; use std::time::Duration; use anyhow::{Context, Result}; use futures::{StreamExt, TryStreamExt}; use prek_consts::env_vars::EnvVars; +use prek_consts::prepend_paths; use rand::RngExt; use rustc_hash::{FxHashMap, FxHashSet}; use tracing::debug; @@ -13,6 +14,21 @@ use crate::languages::ruby::installer::RubyResult; use crate::process::Cmd; use crate::run::CONCURRENCY; +/// Build a `PATH` value with the resolved Ruby's bin directory prepended. +/// +/// `ruby -S gem` searches `$PATH` for the `gem` script. The rv-ruby tarballs +/// that prek auto-downloads ship `gem` next to `ruby` in the same `bin/` +/// directory, but that directory is not on the parent process's PATH (e.g. +/// in a Docker image with no system Ruby). Without prepending it, Ruby errors +/// with `LoadError: No such file or directory -- gem`. +fn ruby_path_env(ruby: &RubyResult) -> Result { + let ruby_bin_dir = ruby + .ruby_bin() + .parent() + .context("Ruby executable should have a parent directory")?; + prepend_paths(&[ruby_bin_dir]).context("Failed to join PATH") +} + /// Find all .gemspec files in a directory fn find_gemspecs(dir: &Path) -> Result> { let mut gemspecs = Vec::new(); @@ -49,6 +65,7 @@ async fn build_gemspec(ruby: &RubyResult, gemspec_path: &Path) -> Result Result } /// Set common gem environment variables for isolation. -fn gem_env<'a>(cmd: &'a mut Cmd, gem_home: &Path) -> &'a mut Cmd { - cmd.env(EnvVars::GEM_HOME, gem_home) +/// +/// Also prepends the resolved Ruby's bin directory to `$PATH` so that +/// `ruby -S gem` can find the bundled `gem` script even when no system Ruby +/// is on PATH. +fn gem_env<'a>(cmd: &'a mut Cmd, ruby: &RubyResult, gem_home: &Path) -> Result<&'a mut Cmd> { + cmd.env(EnvVars::PATH, ruby_path_env(ruby)?) + .env(EnvVars::GEM_HOME, gem_home) .env(EnvVars::BUNDLE_IGNORE_CONFIG, "1") .env_remove(EnvVars::GEM_PATH) .env_remove(EnvVars::BUNDLE_GEMFILE); @@ -97,7 +119,7 @@ fn gem_env<'a>(cmd: &'a mut Cmd, gem_home: &Path) -> &'a mut Cmd { cmd.env("MAKEFLAGS", format!("-j{}", *CONCURRENCY)); } - cmd + Ok(cmd) } /// A gem resolved by `gem install --explain`. @@ -189,7 +211,7 @@ async fn resolve_gems( .arg(gem_home.join("bin")) .args(gem_files) .args(additional_dependencies); - gem_env(&mut cmd, gem_home); + gem_env(&mut cmd, ruby, gem_home)?; let output = cmd.check(true).output().await?; let stdout = String::from_utf8_lossy(&output.stdout); @@ -226,7 +248,7 @@ async fn install_single_gem( } } - gem_env(&mut cmd, gem_home); + gem_env(&mut cmd, ruby, gem_home)?; cmd.check(true).output().await?; Ok(()) } @@ -251,7 +273,7 @@ async fn install_gems_sequential( .arg(gem_home.join("bin")) .args(gem_files) .args(additional_dependencies); - gem_env(&mut cmd, gem_home); + gem_env(&mut cmd, ruby, gem_home)?; debug!("Installing gems sequentially to {}", gem_home.display()); cmd.check(true).output().await?; From 50a3e2586d7bd68bc2230fadf3acfdecf9b03edd Mon Sep 17 00:00:00 2001 From: Jo <10510431+j178@users.noreply.github.com> Date: Thu, 30 Apr 2026 17:47:52 +0800 Subject: [PATCH 04/23] Preserve non-UTF8 filenames from git (#2023) Preserve raw Git path bytes on Unix so non-UTF8 filenames no longer abort file collection. Glob filters now match paths directly; regex filters remain UTF-8-only. Closes #1701 Closes #649 --- crates/prek-identify/src/lib.rs | 34 ++++++++----- crates/prek/src/cli/auto_update/mod.rs | 8 +-- crates/prek/src/cli/run/filter.rs | 50 +++++++++++++++++-- crates/prek/src/config.rs | 57 ++++++++++++---------- crates/prek/src/git.rs | 30 +++++++++++- crates/prek/src/hooks/builtin_hooks/mod.rs | 2 +- crates/prek/src/hooks/meta_hooks.rs | 25 ++++------ 7 files changed, 143 insertions(+), 63 deletions(-) diff --git a/crates/prek-identify/src/lib.rs b/crates/prek-identify/src/lib.rs index bed80cc33..29ebf93a7 100644 --- a/crates/prek-identify/src/lib.rs +++ b/crates/prek-identify/src/lib.rs @@ -18,13 +18,14 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. -use std::borrow::Cow; use std::io::{BufRead, Read}; use std::ops::BitOrAssign; use std::path::Path; #[cfg(feature = "serde")] use serde::de::{Error as DeError, SeqAccess, Visitor}; +#[cfg(any(feature = "serde", feature = "schemars"))] +use std::borrow::Cow; pub mod tags; @@ -300,19 +301,17 @@ pub fn tags_from_path(path: &Path) -> Result { fn tags_from_filename(filename: &Path) -> TagSet { let ext = filename.extension().and_then(|ext| ext.to_str()); - let filename = filename + let mut result = filename .file_name() .and_then(|name| name.to_str()) - .expect("Invalid filename"); - - let mut result = tags::NAMES - .get(filename) - .or_else(|| { - // Allow e.g. "Dockerfile.xenial" to match "Dockerfile". - filename - .split('.') - .next() - .and_then(|name| tags::NAMES.get(name)) + .and_then(|filename| { + tags::NAMES.get(filename).or_else(|| { + // Allow e.g. "Dockerfile.xenial" to match "Dockerfile". + filename + .split('.') + .next() + .and_then(|name| tags::NAMES.get(name)) + }) }) .copied() .unwrap_or_default(); @@ -597,6 +596,17 @@ mod tests { assert_tagset(&tags, &["text", "tiltfile"]); } + #[cfg(unix)] + #[test] + fn tags_from_non_utf8_filename_uses_utf8_extension_when_available() { + use std::ffi::OsStr; + use std::os::unix::ffi::OsStrExt as _; + + let tags = super::tags_from_filename(Path::new(OsStr::from_bytes(b"bad-\xff.py"))); + + assert_tagset(&tags, &["python", "text"]); + } + #[test] fn tags_from_interpreter() { let tags = super::tags_from_interpreter("/usr/bin/python3"); diff --git a/crates/prek/src/cli/auto_update/mod.rs b/crates/prek/src/cli/auto_update/mod.rs index 00bcf5357..fd02f795f 100644 --- a/crates/prek/src/cli/auto_update/mod.rs +++ b/crates/prek/src/cli/auto_update/mod.rs @@ -187,19 +187,19 @@ impl TagFilters { /// Repo-specific include filters override global include filters for that repo. fn is_included(&self, repo: &str, tag: &str) -> bool { if let Some(repo_include) = self.repo_include.get(repo) { - return repo_include.is_empty() || repo_include.is_match(tag); + return repo_include.is_empty() || repo_include.is_match(Path::new(tag)); } - self.global_include.is_empty() || self.global_include.is_match(tag) + self.global_include.is_empty() || self.global_include.is_match(Path::new(tag)) } /// Returns whether a tag matches any global or repo-specific exclude filter. fn is_excluded(&self, repo: &str, tag: &str) -> bool { - self.global_exclude.is_match(tag) + self.global_exclude.is_match(Path::new(tag)) || self .repo_exclude .get(repo) - .is_some_and(|set| set.is_match(tag)) + .is_some_and(|set| set.is_match(Path::new(tag))) } } diff --git a/crates/prek/src/cli/run/filter.rs b/crates/prek/src/cli/run/filter.rs index e1ea7ed12..75ea8973b 100644 --- a/crates/prek/src/cli/run/filter.rs +++ b/crates/prek/src/cli/run/filter.rs @@ -27,9 +27,6 @@ impl<'a> FilenameFilter<'a> { } pub(crate) fn filter(&self, filename: &Path) -> bool { - let Some(filename) = filename.to_str() else { - return false; - }; if let Some(pattern) = &self.include { if !pattern.is_match(filename) { return false; @@ -399,6 +396,10 @@ mod tests { FilePattern::Glob(GlobPatterns::new(vec![pattern.to_string()]).unwrap()) } + fn regex_pattern(pattern: &str) -> FilePattern { + FilePattern::regex(pattern).unwrap() + } + #[test] fn filename_filter_supports_glob_include_and_exclude() { let include = glob_pattern("src/**/*.rs"); @@ -409,4 +410,47 @@ mod tests { assert!(!filter.filter(Path::new("src/lib/ignored.rs"))); assert!(!filter.filter(Path::new("tests/main.rs"))); } + + #[cfg(unix)] + #[test] + fn filename_filter_allows_non_utf8_paths_without_patterns() { + use std::ffi::OsStr; + use std::os::unix::ffi::OsStrExt as _; + + let path = Path::new(OsStr::from_bytes(b"bad-\xff.py")); + let filter = FilenameFilter::new(None, None); + + assert!(filter.filter(path)); + } + + #[cfg(unix)] + #[test] + fn filename_filter_matches_non_utf8_paths_with_glob_patterns() { + use std::ffi::OsStr; + use std::os::unix::ffi::OsStrExt as _; + + let include = glob_pattern("**/*.py"); + let exclude = glob_pattern("**/*.py"); + let path = Path::new(OsStr::from_bytes(b"bad-\xff.py")); + let filter = FilenameFilter::new(Some(&include), None); + + assert!(filter.filter(path)); + + let filter = FilenameFilter::new(None, Some(&exclude)); + + assert!(!filter.filter(path)); + } + + #[cfg(unix)] + #[test] + fn filename_filter_skips_non_utf8_paths_with_regex_include() { + use std::ffi::OsStr; + use std::os::unix::ffi::OsStrExt as _; + + let include = regex_pattern(r".*\.py$"); + let path = Path::new(OsStr::from_bytes(b"bad-\xff.py")); + let filter = FilenameFilter::new(Some(&include), None); + + assert!(!filter.filter(path)); + } } diff --git a/crates/prek/src/config.rs b/crates/prek/src/config.rs index efcb6601f..d4f39eeba 100644 --- a/crates/prek/src/config.rs +++ b/crates/prek/src/config.rs @@ -40,8 +40,8 @@ impl GlobPatterns { self.patterns.is_empty() } - pub(crate) fn is_match(&self, value: &str) -> bool { - self.set.is_match(Path::new(value)) + pub(crate) fn is_match(&self, path: &Path) -> bool { + self.set.is_match(path) } } @@ -182,19 +182,22 @@ pub(crate) enum FilePattern { } impl FilePattern { - pub(crate) fn new_glob(patterns: Vec) -> Result { + pub(crate) fn glob(patterns: Vec) -> Result { Ok(Self::Glob(GlobPatterns::new(patterns)?)) } - pub(crate) fn new_regex(pattern: &str) -> Result { + pub(crate) fn regex(pattern: &str) -> Result { Ok(Self::Regex(Regex::new(pattern)?)) } - pub(crate) fn is_match(&self, str: &str) -> bool { + pub(crate) fn is_match(&self, path: &Path) -> bool { match self { FilePattern::Never => false, - FilePattern::Regex(regex) => regex.is_match(str).unwrap_or(false), - FilePattern::Glob(globs) => globs.is_match(str), + // Regex patterns are text matchers; globs can match OS paths directly. + FilePattern::Regex(regex) => path + .to_str() + .is_some_and(|path| regex.is_match(path).unwrap_or(false)), + FilePattern::Glob(globs) => globs.is_match(path), } } } @@ -1460,9 +1463,9 @@ mod tests { matches!(parsed.files, FilePattern::Regex(_)), "expected regex pattern" ); - assert!(parsed.files.is_match("src/main.rs")); - assert!(!parsed.files.is_match("other/main.rs")); - assert!(parsed.exclude.is_match("target/debug/app")); + assert!(parsed.files.is_match(Path::new("src/main.rs"))); + assert!(!parsed.files.is_match(Path::new("other/main.rs"))); + assert!(parsed.exclude.is_match(Path::new("target/debug/app"))); let glob_yaml = indoc::indoc! {r" files: @@ -1476,10 +1479,10 @@ mod tests { matches!(parsed.files, FilePattern::Glob(_)), "expected glob pattern" ); - assert!(parsed.files.is_match("src/lib/main.rs")); - assert!(!parsed.files.is_match("src/lib/main.py")); - assert!(parsed.exclude.is_match("target/debug/app")); - assert!(!parsed.exclude.is_match("src/lib/main.rs")); + assert!(parsed.files.is_match(Path::new("src/lib/main.rs"))); + assert!(!parsed.files.is_match(Path::new("src/lib/main.py"))); + assert!(parsed.exclude.is_match(Path::new("target/debug/app"))); + assert!(!parsed.exclude.is_match(Path::new("src/lib/main.rs"))); let glob_list_yaml = indoc::indoc! {r" files: @@ -1493,11 +1496,11 @@ mod tests { "}; let parsed: Wrapper = serde_saphyr::from_str(glob_list_yaml).expect("glob list patterns should parse"); - assert!(parsed.files.is_match("src/lib/main.rs")); - assert!(parsed.files.is_match("crates/foo/src/lib.rs")); - assert!(!parsed.files.is_match("tests/main.rs")); - assert!(parsed.exclude.is_match("target/debug/app")); - assert!(parsed.exclude.is_match("dist/app")); + assert!(parsed.files.is_match(Path::new("src/lib/main.rs"))); + assert!(parsed.files.is_match(Path::new("crates/foo/src/lib.rs"))); + assert!(!parsed.files.is_match(Path::new("tests/main.rs"))); + assert!(parsed.exclude.is_match(Path::new("target/debug/app"))); + assert!(parsed.exclude.is_match(Path::new("dist/app"))); } #[test] @@ -1512,24 +1515,24 @@ mod tests { pattern.to_string(), "glob: [src/**/*.rs, crates/**/src/**/*.rs]" ); - assert!(pattern.is_match("src/main.rs")); - assert!(pattern.is_match("crates/foo/src/lib.rs")); - assert!(!pattern.is_match("tests/main.rs")); + assert!(pattern.is_match(Path::new("src/main.rs"))); + assert!(pattern.is_match(Path::new("crates/foo/src/lib.rs"))); + assert!(!pattern.is_match(Path::new("tests/main.rs"))); } #[test] fn file_pattern_never_matches() { let pattern = FilePattern::Never; - assert!(!pattern.is_match("")); - assert!(!pattern.is_match("foo.txt")); - assert!(!pattern.is_match("nested/path.rs")); + assert!(!pattern.is_match(Path::new(""))); + assert!(!pattern.is_match(Path::new("foo.txt"))); + assert!(!pattern.is_match(Path::new("nested/path.rs"))); } #[test] fn empty_glob_list_matches_nothing() { let pattern = serde_saphyr::from_str::("glob: []").unwrap(); - assert!(!pattern.is_match("any/file.rs")); - assert!(!pattern.is_match("")); + assert!(!pattern.is_match(Path::new("any/file.rs"))); + assert!(!pattern.is_match(Path::new(""))); } #[test] diff --git a/crates/prek/src/git.rs b/crates/prek/src/git.rs index f9aceb25b..13310c4a8 100644 --- a/crates/prek/src/git.rs +++ b/crates/prek/src/git.rs @@ -86,10 +86,24 @@ pub(crate) fn git_cmd(summary: &str) -> Result { fn zsplit(s: &[u8]) -> Result, Utf8Error> { s.split(|&b| b == b'\0') .filter(|slice| !slice.is_empty()) - .map(|slice| str::from_utf8(slice).map(PathBuf::from)) + .map(path_from_git_bytes) .collect() } +#[cfg(unix)] +#[expect(clippy::unnecessary_wraps)] +fn path_from_git_bytes(bytes: &[u8]) -> Result { + use std::ffi::OsStr; + use std::os::unix::ffi::OsStrExt as _; + + Ok(PathBuf::from(OsStr::from_bytes(bytes))) +} + +#[cfg(not(unix))] +fn path_from_git_bytes(bytes: &[u8]) -> Result { + str::from_utf8(bytes).map(PathBuf::from) +} + pub(crate) async fn intent_to_add_files(root: &Path) -> Result, Error> { let output = git_cmd("get intent to add files")? .arg("diff") @@ -859,6 +873,20 @@ pub(crate) fn list_submodules(git_root: &Path) -> Result, Error> { #[cfg(test)] mod tests { use super::shared_repository_file_mode; + #[cfg(unix)] + use super::zsplit; + + #[cfg(unix)] + #[test] + fn zsplit_preserves_non_utf8_paths() { + use std::os::unix::ffi::OsStrExt as _; + + let paths = zsplit(b"normal.py\0bad-\xff.py\0").unwrap(); + + assert_eq!(paths.len(), 2); + assert_eq!(paths[0].as_os_str().as_bytes(), b"normal.py"); + assert_eq!(paths[1].as_os_str().as_bytes(), b"bad-\xff.py"); + } #[test] fn shared_repository_group_mode_matches_git_behavior() { diff --git a/crates/prek/src/hooks/builtin_hooks/mod.rs b/crates/prek/src/hooks/builtin_hooks/mod.rs index 372ac22bf..95640c8a3 100644 --- a/crates/prek/src/hooks/builtin_hooks/mod.rs +++ b/crates/prek/src/hooks/builtin_hooks/mod.rs @@ -164,7 +164,7 @@ impl BuiltinHook { "checks for filenames which cannot be created on Windows.".to_string(), ), files: Some( - FilePattern::new_regex( + FilePattern::regex( check_illegal_windows_names::ILLEGAL_WINDOWS_PATTERN, ) .expect("builtin files regex must be valid"), diff --git a/crates/prek/src/hooks/meta_hooks.rs b/crates/prek/src/hooks/meta_hooks.rs index ba6d483bf..a1e82a08a 100644 --- a/crates/prek/src/hooks/meta_hooks.rs +++ b/crates/prek/src/hooks/meta_hooks.rs @@ -53,8 +53,7 @@ impl MetaHook { pub(crate) fn from_id(id: &str) -> Result { let hook_id = MetaHooks::from_str(id).map_err(|_| ())?; let config_file_glob = - FilePattern::new_glob(CONFIG_FILENAMES.iter().map(ToString::to_string).collect()) - .unwrap(); + FilePattern::glob(CONFIG_FILENAMES.iter().map(ToString::to_string).collect()).unwrap(); Ok(match hook_id { MetaHooks::CheckHooksApply => MetaHook { @@ -146,17 +145,13 @@ fn excludes_any( } files.iter().any(|f| { - let Some(f) = f.as_ref().to_str() else { - return false; // Skip files that cannot be converted to a string - }; - if let Some(pattern) = &include { - if !pattern.is_match(f) { + if !pattern.is_match(f.as_ref()) { return false; } } if let Some(pattern) = &exclude { - if !pattern.is_match(f) { + if !pattern.is_match(f.as_ref()) { return false; } } @@ -271,7 +266,7 @@ mod tests { use prek_consts::{PRE_COMMIT_CONFIG_YAML, PRE_COMMIT_CONFIG_YML, PREK_TOML}; fn regex_pattern(pattern: &str) -> FilePattern { - FilePattern::new_regex(pattern).unwrap() + FilePattern::regex(pattern).unwrap() } #[test] @@ -299,15 +294,15 @@ mod tests { fn meta_hook_patterns_cover_config_files() { let apply = MetaHook::from_id("check-hooks-apply").expect("known meta hook"); let apply_files = apply.options.files.as_ref().expect("files should be set"); - assert!(apply_files.is_match(PRE_COMMIT_CONFIG_YAML)); - assert!(apply_files.is_match(PRE_COMMIT_CONFIG_YML)); - assert!(apply_files.is_match(PREK_TOML)); + assert!(apply_files.is_match(Path::new(PRE_COMMIT_CONFIG_YAML))); + assert!(apply_files.is_match(Path::new(PRE_COMMIT_CONFIG_YML))); + assert!(apply_files.is_match(Path::new(PREK_TOML))); let useless = MetaHook::from_id("check-useless-excludes").expect("known meta hook"); let useless_files = useless.options.files.as_ref().expect("files should be set"); - assert!(useless_files.is_match(PRE_COMMIT_CONFIG_YAML)); - assert!(useless_files.is_match(PRE_COMMIT_CONFIG_YML)); - assert!(useless_files.is_match(PREK_TOML)); + assert!(useless_files.is_match(Path::new(PRE_COMMIT_CONFIG_YAML))); + assert!(useless_files.is_match(Path::new(PRE_COMMIT_CONFIG_YML))); + assert!(useless_files.is_match(Path::new(PREK_TOML))); let identity = MetaHook::from_id("identity").expect("known meta hook"); assert!(identity.options.files.is_none()); From b378c6ea94a88fa38bcf0fe5d2c2873b4f38ce01 Mon Sep 17 00:00:00 2001 From: Jo <10510431+j178@users.noreply.github.com> Date: Fri, 1 May 2026 18:22:09 +0800 Subject: [PATCH 05/23] Update logo and icon (#2025) --- README.md | 7 +------ docs/assets/favicon.ico | Bin 15406 -> 22382 bytes docs/assets/logo.png | Bin 0 -> 236257 bytes docs/assets/logo.webp | Bin 44258 -> 0 bytes docs/index.md | 2 +- mkdocs.yml | 2 +- uv.lock | 2 +- 7 files changed, 4 insertions(+), 9 deletions(-) create mode 100644 docs/assets/logo.png delete mode 100644 docs/assets/logo.webp diff --git a/README.md b/README.md index 43f70617a..d43a733b3 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,6 @@
-

-prek - -prek - -

+prek [![prek](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/j178/prek/master/docs/assets/badge-v0.json)](https://github.com/j178/prek) [![PyPI version](https://img.shields.io/pypi/v/prek.svg)](https://pypi.python.org/pypi/prek) diff --git a/docs/assets/favicon.ico b/docs/assets/favicon.ico index d7abd918a5adfe0b4745bfc65fd9f9999eb0e499..23f9368a47129dd07d10c7256a080be727bb49ca 100644 GIT binary patch literal 22382 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 literal 15406 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 diff --git a/docs/assets/logo.png b/docs/assets/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..f7c31e7621c7f3a79678e620fc24bffd5417cdb1 GIT binary patch literal 236257 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­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

4VPKR&&K4F<92Y*R#~4i)m~OZc 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 - prek + prek

--8<-- "README.md:description" diff --git a/mkdocs.yml b/mkdocs.yml index 12433b36a..862e91292 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -10,7 +10,7 @@ copyright: Copyright © 2026 j178 theme: name: material - logo: assets/logo.webp + logo: assets/logo.png favicon: assets/favicon.ico palette: - media: "(prefers-color-scheme)" diff --git a/uv.lock b/uv.lock index 208781b08..c13f73ec5 100644 --- a/uv.lock +++ b/uv.lock @@ -433,7 +433,7 @@ wheels = [ [[package]] name = "prek" -version = "0.3.10" +version = "0.3.11" source = { virtual = "." } [package.dev-dependencies] From 384c883217e027a82c8a93036886651b2240c175 Mon Sep 17 00:00:00 2001 From: Jo <10510431+j178@users.noreply.github.com> Date: Sat, 2 May 2026 01:01:30 +0800 Subject: [PATCH 06/23] Remove rayon from file filtering (#2026) --- Cargo.lock | 21 --------------------- Cargo.toml | 1 - crates/prek/Cargo.toml | 1 - crates/prek/src/cli/run/filter.rs | 5 ++--- 4 files changed, 2 insertions(+), 26 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9fde80ca7..7dbf47464 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2159,7 +2159,6 @@ dependencies = [ "pretty_assertions", "quick-xml 0.39.2", "rand 0.10.1", - "rayon", "regex", "reqwest", "rustc-hash", @@ -2408,26 +2407,6 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c8d0fd677905edcbeedbf2edb6494d676f0e98d54d5cf9bda0b061cb8fb8aba" -[[package]] -name = "rayon" -version = "1.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb39b166781f92d482534ef4b4b1b2568f42613b53e5b6c160e24cfbfa30926d" -dependencies = [ - "either", - "rayon-core", -] - -[[package]] -name = "rayon-core" -version = "1.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91" -dependencies = [ - "crossbeam-deque", - "crossbeam-utils", -] - [[package]] name = "redox_syscall" version = "0.7.3" diff --git a/Cargo.toml b/Cargo.toml index 53176682e..c6ac9362e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -64,7 +64,6 @@ phf = { version = "0.13.1", default-features = false, features = ["macros"] } pprof = { version = "0.15.0" } quick-xml = { version = "0.39" } rand = { version = "0.10.0" } -rayon = { version = "1.10.0" } reqwest = { version = "0.13.2", default-features = false, features = [ "http2", "stream", diff --git a/crates/prek/Cargo.toml b/crates/prek/Cargo.toml index a45869b32..f9c6053a4 100644 --- a/crates/prek/Cargo.toml +++ b/crates/prek/Cargo.toml @@ -63,7 +63,6 @@ owo-colors = { workspace = true } path-clean = { workspace = true } quick-xml = { workspace = true } rand = { workspace = true } -rayon = { workspace = true } reqwest = { workspace = true } rustc-hash = { workspace = true } same-file = { workspace = true } diff --git a/crates/prek/src/cli/run/filter.rs b/crates/prek/src/cli/run/filter.rs index 75ea8973b..ac88b8c05 100644 --- a/crates/prek/src/cli/run/filter.rs +++ b/crates/prek/src/cli/run/filter.rs @@ -5,7 +5,6 @@ use itertools::{Either, Itertools}; use path_clean::PathClean; use prek_consts::env_vars::EnvVars; use prek_identify::{TagSet, tags_from_path}; -use rayon::iter::{IntoParallelRefIterator, ParallelIterator}; use rustc_hash::FxHashSet; use tracing::{debug, error, instrument}; @@ -151,7 +150,7 @@ impl<'a> FileFilter<'a> { let filter = FileTagFilter::new(types, types_or, exclude_types); let filenames: Vec<_> = self .filenames - .par_iter() + .iter() .filter(|filename| match tags_from_path(filename) { Ok(tags) => filter.filter(&tags), Err(err) => { @@ -171,7 +170,7 @@ impl<'a> FileFilter<'a> { // Filter by hook `files` and `exclude` patterns. let filter = FilenameFilter::new(hook.files.as_ref(), hook.exclude.as_ref()); - let filenames = self.filenames.par_iter().filter(|filename| { + let filenames = self.filenames.iter().filter(|filename| { // Strip the project-relative prefix before applying hook-level include/exclude patterns. if let Ok(relative) = filename.strip_prefix(&self.filename_prefix) { filter.filter(relative) From 1032602db323fb85b5a6674987d8faff64efd059 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 2 May 2026 01:43:37 +0800 Subject: [PATCH 07/23] Update leafo/gh-actions-lua action to v13 (#2028) --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 58c37535f..ebed7b5dd 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -522,7 +522,7 @@ jobs: - name: "Install Lua" if: ${{ contains(format(' {0} ', matrix.languages), ' lua ') }} - uses: leafo/gh-actions-lua@8c9e175e7a3d77e21f809eefbee34a19b858641b # v12 + uses: leafo/gh-actions-lua@6919171ccf181b826f44b9bca76307b577217377 # v13.0.0 with: luaVersion: ${{ env.LUA_VERSION }} From ddcb62794a7245cde0cd565ca27d1c36a8f60f47 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 2 May 2026 01:44:03 +0800 Subject: [PATCH 08/23] Update Rust crate fancy-regex to 0.18.0 (#2027) --- Cargo.lock | 19 +++++++++---------- Cargo.toml | 2 +- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7dbf47464..198913e69 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -792,7 +792,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] @@ -807,9 +807,9 @@ dependencies = [ [[package]] name = "fancy-regex" -version = "0.17.0" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72cf461f865c862bb7dc573f643dd6a2b6842f7c30b07882b56bd148cc2761b8" +checksum = "e1e1dacd0d2082dfcf1351c4bdd566bbe89a2b263235a2b50058f1e130a47277" dependencies = [ "bit-set", "regex-automata", @@ -1488,7 +1488,7 @@ checksum = "3640c1c38b8e4e43584d8df18be5fc6b0aa314ce6ebf51b53313d4306cca8e46" dependencies = [ "hermit-abi", "libc", - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] @@ -2337,7 +2337,7 @@ dependencies = [ "once_cell", "socket2", "tracing", - "windows-sys 0.52.0", + "windows-sys 0.60.2", ] [[package]] @@ -2551,7 +2551,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys", - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] @@ -2608,7 +2608,7 @@ dependencies = [ "security-framework", "security-framework-sys", "webpki-root-certs", - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] @@ -2945,7 +2945,6 @@ dependencies = [ "cfg-if", "libc", "psm", - "windows-sys 0.52.0", "windows-sys 0.59.0", ] @@ -3079,7 +3078,7 @@ dependencies = [ "getrandom 0.4.2", "once_cell", "rustix", - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] @@ -3730,7 +3729,7 @@ version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index c6ac9362e..a5c26bbbd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -40,7 +40,7 @@ clap_complete = { version = "4.6.0", features = ["unstable-dynamic"] } ctrlc = { version = "3.4.5" } dunce = { version = "1.0.5" } etcetera = { version = "0.11.0" } -fancy-regex = { version = "0.17.0" } +fancy-regex = { version = "0.18.0" } fs-err = { version = "3.3.0", features = ["tokio"] } futures = { version = "0.3.31" } hex = { version = "0.4.3" } From ea786861145adfd4531043e6645ac596bda58487 Mon Sep 17 00:00:00 2001 From: Bill ZHANG <36790218+Lutra-Fs@users.noreply.github.com> Date: Sun, 3 May 2026 04:57:14 +1000 Subject: [PATCH 09/23] Support `language: dart` (#1146) Implements full Dart language support following TDD approach: - Migrated tests from pre-commit's test suite - Implemented Dart language handler in src/languages/dart.rs - System Dart installation detection - pubspec.yaml dependency installation via `dart pub get` - Additional dependencies via `dart pub cache add` - Environment setup with PUB_CACHE - Added comprehensive test suite covering: - Health checks - Script execution with file arguments - pubspec.yaml handling - Additional dependencies (with and without versions) - Environment variable setup - Error handling - Updated documentation in docs/todo.md Language features: - Uses system-installed Dart (no version management) - Supports additional_dependencies - Supports environment setup - Compatible with pre-commit Dart hooks Closes #51 --------- Co-authored-by: Jo <10510431+j178@users.noreply.github.com> --- .config/nextest.toml | 2 +- .github/workflows/ci.yml | 59 +-- crates/prek-consts/src/env_vars.rs | 3 + crates/prek/src/hook_entry.rs | 4 + crates/prek/src/languages/dart.rs | 534 ++++++++++++++++++++++++++ crates/prek/src/languages/mod.rs | 19 +- crates/prek/tests/languages/dart.rs | 575 ++++++++++++++++++++++++++++ crates/prek/tests/languages/main.rs | 1 + docs/languages.md | 56 ++- docs/proposals/hook-shell.md | 3 +- docs/reference/configuration.md | 3 +- 11 files changed, 1223 insertions(+), 36 deletions(-) create mode 100644 crates/prek/src/languages/dart.rs create mode 100644 crates/prek/tests/languages/dart.rs diff --git a/.config/nextest.toml b/.config/nextest.toml index a2b183f62..800d2fd2d 100644 --- a/.config/nextest.toml +++ b/.config/nextest.toml @@ -2,7 +2,7 @@ # Exclude heavy language-specific integration tests from the main CI runs. # Keep this as a deny-list so new language test modules run in ci-core until # they are deliberately moved to the language-test matrix. -default-filter = "not binary_id(prek::languages) or (binary_id(prek::languages) and not (test(bun::) or test(deno::) or test(docker::) or test(docker_image::) or test(dotnet::) or test(golang::) or test(haskell::) or test(julia::) or test(lua::) or test(node::) or test(python::) or test(ruby::) or test(rust::) or test(swift::)))" +default-filter = "not binary_id(prek::languages) or (binary_id(prek::languages) and not (test(bun::) or test(dart::) or test(deno::) or test(docker::) or test(docker_image::) or test(dotnet::) or test(golang::) or test(haskell::) or test(julia::) or test(lua::) or test(node::) or test(python::) or test(ruby::) or test(rust::) or test(swift::)))" status-level = "skip" final-status-level = "slow" failure-output = "immediate" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ebed7b5dd..06a984405 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -28,6 +28,7 @@ env: JULIA_VERSION: "1.12.4" DOTNET_VERSION: "10.0" DENO_VERSION: "2" + DART_VERSION: "3.10.4" # Cargo env vars CARGO_INCREMENTAL: 0 @@ -413,56 +414,56 @@ jobs: include: - os: ubuntu-latest group: 1 - languages: bun deno docker - filter: test(bun::) or test(deno::) or test(docker::) or test(docker_image::) + languages: bun dart deno + filter: test(bun::) or test(dart::) or test(deno::) - os: ubuntu-latest group: 2 - languages: dotnet golang haskell - filter: test(dotnet::) or test(golang::) or test(haskell::) + languages: docker dotnet golang + filter: test(docker::) or test(docker_image::) or test(dotnet::) or test(golang::) - os: ubuntu-latest group: 3 - languages: julia lua node - filter: test(julia::) or test(lua::) or test(node::) + languages: haskell julia lua + filter: test(haskell::) or test(julia::) or test(lua::) - os: ubuntu-latest group: 4 - languages: python ruby rust - filter: test(python::) or test(ruby::) or test(rust::) + languages: node python ruby + filter: test(node::) or test(python::) or test(ruby::) - os: ubuntu-latest group: 5 - languages: swift - filter: test(swift::) + languages: rust swift + filter: test(rust::) or test(swift::) - os: macos-latest group: 1 - languages: bun deno dotnet - filter: test(bun::) or test(deno::) or test(dotnet::) + languages: bun dart deno + filter: test(bun::) or test(dart::) or test(deno::) - os: macos-latest group: 2 - languages: golang julia lua - filter: test(golang::) or test(julia::) or test(lua::) + languages: dotnet golang julia + filter: test(dotnet::) or test(golang::) or test(julia::) - os: macos-latest group: 3 - languages: node python ruby - filter: test(node::) or test(python::) or test(ruby::) + languages: lua node python + filter: test(lua::) or test(node::) or test(python::) - os: macos-latest group: 4 - languages: rust swift - filter: test(rust::) or test(swift::) + languages: ruby rust swift + filter: test(ruby::) or test(rust::) or test(swift::) - os: windows-latest group: 1 - languages: bun deno dotnet - filter: test(bun::) or test(deno::) or test(dotnet::) + languages: bun dart deno + filter: test(bun::) or test(dart::) or test(deno::) - os: windows-latest group: 2 - languages: golang haskell julia - filter: test(golang::) or test(haskell::) or test(julia::) + languages: dotnet golang haskell + filter: test(dotnet::) or test(golang::) or test(haskell::) - os: windows-latest group: 3 - languages: lua node python - filter: test(lua::) or test(node::) or test(python::) + languages: julia lua node + filter: test(julia::) or test(lua::) or test(node::) - os: windows-latest group: 4 - languages: ruby rust - filter: test(ruby::) or test(rust::) + languages: python ruby rust + filter: test(python::) or test(ruby::) or test(rust::) steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: @@ -550,6 +551,12 @@ jobs: with: deno-version: ${{ env.DENO_VERSION }} + - name: "Install Dart" + if: ${{ contains(format(' {0} ', matrix.languages), ' dart ') }} + uses: dart-lang/setup-dart@0a8a0fc875eb934c15d08629302413c671d3f672 # v1.6.5 + with: + sdk: ${{ env.DART_VERSION }} + - name: "Install GHC and Cabal" if: ${{ contains(format(' {0} ', matrix.languages), ' haskell ') }} uses: haskell-actions/setup@cd0d9bdd65b20557f41bea4dbe43d0b5fbbfe553 # v2.11.0 diff --git a/crates/prek-consts/src/env_vars.rs b/crates/prek-consts/src/env_vars.rs index 8903bf32f..cc830dddd 100644 --- a/crates/prek-consts/src/env_vars.rs +++ b/crates/prek-consts/src/env_vars.rs @@ -85,6 +85,9 @@ impl EnvVars { pub const LUA_PATH: &'static str = "LUA_PATH"; pub const LUA_CPATH: &'static str = "LUA_CPATH"; + // Dart related + pub const PUB_CACHE: &'static str = "PUB_CACHE"; + // Ruby related pub const PREK_RUBY_MIRROR: &'static str = "PREK_RUBY_MIRROR"; pub const GEM_HOME: &'static str = "GEM_HOME"; diff --git a/crates/prek/src/hook_entry.rs b/crates/prek/src/hook_entry.rs index b142955b9..3a9fed121 100644 --- a/crates/prek/src/hook_entry.rs +++ b/crates/prek/src/hook_entry.rs @@ -33,6 +33,10 @@ impl PreparedHookEntry { pub(crate) fn argv(&self) -> &[String] { &self.argv } + + pub(crate) fn argv_mut(&mut self) -> &mut Vec { + &mut self.argv + } } impl Deref for PreparedHookEntry { diff --git a/crates/prek/src/languages/dart.rs b/crates/prek/src/languages/dart.rs new file mode 100644 index 000000000..7fd8e5676 --- /dev/null +++ b/crates/prek/src/languages/dart.rs @@ -0,0 +1,534 @@ +//! A Dart package is described by `pubspec.yaml`. The package `name` is what +//! other packages depend on, `dependencies` are resolved by `dart pub get`, and +//! `executables` declares command names that map to Dart files under `bin/`. +//! For executable entries, Dart treats a null value as "use the command name as +//! the entrypoint"; this module also treats an empty string that way. +//! +//! `dart pub get` writes `.dart_tool/package_config.json`, which is the package +//! resolver map used by the Dart VM. `prek` creates a pubspec in the hook env, +//! runs `dart pub get` there with `PUB_CACHE` pointed at the env, and passes the +//! generated package config to hook commands that run `dart run` or direct +//! `.dart` scripts. + +use std::collections::BTreeMap; +use std::env::consts::EXE_EXTENSION; +use std::path::{Path, PathBuf}; +use std::process::Stdio; +use std::sync::Arc; + +use anyhow::{Context, Result}; +use prek_consts::env_vars::EnvVars; +use prek_consts::prepend_paths; +use serde::{Deserialize, Serialize}; +use tracing::debug; + +use crate::cli::reporter::{HookInstallReporter, HookRunReporter}; +use crate::hook::{Hook, InstallInfo, InstalledHook}; +use crate::languages::LanguageImpl; +use crate::process::Cmd; +use crate::run::run_by_batch; +use crate::store::Store; + +#[derive(Debug, Copy, Clone)] +pub(crate) struct Dart; + +const PUBSPEC_YAML: &str = "pubspec.yaml"; + +/// Dart package manifest data from `pubspec.yaml`. +/// +/// Format reference: . +#[derive(Debug, Deserialize, Serialize)] +struct Pubspec { + name: String, + #[serde( + default, + skip_deserializing, + skip_serializing_if = "BTreeMap::is_empty" + )] + environment: BTreeMap, + #[serde( + default, + skip_deserializing, + skip_serializing_if = "BTreeMap::is_empty" + )] + dependencies: BTreeMap, + #[serde(default, skip_serializing_if = "BTreeMap::is_empty")] + executables: BTreeMap, +} + +#[derive(Debug, Deserialize, Serialize)] +#[serde(untagged)] +enum PubspecExecutable { + Entrypoint(String), + Default, +} + +#[derive(Debug, Deserialize, Serialize)] +#[serde(untagged)] +enum PubspecDependency { + Version(String), + Path { path: PathBuf }, +} + +impl PubspecExecutable { + /// Convert Dart's executable shorthand into the entrypoint name under `bin/`. + fn into_entrypoint(self, output_name: &str) -> String { + match self { + Self::Entrypoint(entrypoint) if !entrypoint.is_empty() => entrypoint, + Self::Entrypoint(_) | Self::Default => output_name.to_string(), + } + } +} + +/// Resolve the Dart binary that should own this hook environment. +fn find_dart_binary() -> Result { + let dart = which::which("dart") + .context("Failed to locate dart executable. Is Dart installed and available in PATH?")?; + Ok(dart) +} + +impl LanguageImpl for Dart { + async fn install( + &self, + hook: Arc, + store: &Store, + reporter: &HookInstallReporter, + ) -> Result { + let progress = reporter.on_install_start(&hook); + + let mut info = InstallInfo::new( + hook.language, + hook.env_key_dependencies().clone(), + &store.hooks_dir(), + )?; + + debug!(%hook, target = %info.env_path.display(), "Installing Dart environment"); + + let dart = find_dart_binary()?; + + let source_path = hook.repo_path().unwrap_or_else(|| hook.work_dir()); + if source_path.join(PUBSPEC_YAML).exists() { + install_from_pubspec( + &dart, + &info.env_path, + source_path, + &hook.additional_dependencies, + ) + .await?; + } else if !hook.additional_dependencies.is_empty() { + install_package_config( + &dart, + &info.env_path, + None, + None, + &hook.additional_dependencies, + ) + .await + .context("Failed to install Dart additional dependencies")?; + } + + info.with_toolchain(dart); + info.persist_env_path(); + + reporter.on_install_complete(progress); + + Ok(InstalledHook::Installed { + hook, + info: Arc::new(info), + }) + } + + async fn check_health(&self, info: &InstallInfo) -> Result<()> { + let dart = find_dart_binary()?; + + if dart != info.toolchain { + anyhow::bail!( + "Dart executable mismatch: expected `{}`, found `{}`", + info.toolchain.display(), + dart.display() + ); + } + + Ok(()) + } + + async fn run( + &self, + hook: &InstalledHook, + filenames: &[&Path], + store: &Store, + reporter: &HookRunReporter, + ) -> Result<(i32, Vec)> { + let progress = reporter.on_run_start(hook, filenames.len()); + + let env_dir = hook.env_path().expect("Dart must have env path"); + let bin_path = bin_path(env_dir); + let new_path = prepend_paths(&[&bin_path]).context("Failed to join PATH")?; + let packages_path = package_config_path(env_dir); + + let mut entry = hook.entry.resolve(Some(&new_path), store)?; + // `dart pub get` writes the hook env's dependency graph here. Dart's + // VM-level `--packages` flag makes `Platform.packageConfig` and package + // imports resolve against this env instead of the hook work dir. + if packages_path.exists() + && let Some(index) = packages_arg_insert_position(entry.argv(), &hook.args) + { + entry + .argv_mut() + .insert(index, format!("--packages={}", packages_path.display())); + } + + let run = async |batch: &[&Path]| { + let mut output = Cmd::new(&entry[0], "run dart command") + .current_dir(hook.work_dir()) + .args(&entry[1..]) + .env(EnvVars::PATH, &new_path) + .env(EnvVars::PUB_CACHE, env_dir) + .envs(&hook.env) + .args(&hook.args) + .args(batch) + .check(false) + .stdin(Stdio::null()) + .pty_output() + .await?; + + reporter.on_run_progress(progress, batch.len() as u64); + + output.stdout.extend(output.stderr); + let code = output.status.code().unwrap_or(1); + anyhow::Ok((code, output.stdout)) + }; + + let results = run_by_batch(hook, filenames, entry.argv(), run).await?; + + reporter.on_run_complete(progress); + + let mut combined_status = 0; + let mut combined_output = Vec::new(); + for (code, output) in results { + combined_status |= code; + combined_output.extend(output); + } + + Ok((combined_status, combined_output)) + } +} + +/// Return the env directory containing compiled Dart executables. +fn bin_path(env_path: &Path) -> PathBuf { + env_path.join("bin") +} + +/// Return the package config generated by `dart pub get` inside an env. +fn package_config_path(env_path: &Path) -> PathBuf { + env_path.join(".dart_tool").join("package_config.json") +} + +/// Return the `entry` argv position where `--packages=...` should be inserted. +fn packages_arg_insert_position(entry: &[String], hook_args: &[String]) -> Option { + fn is_dart_binary(arg: &str) -> bool { + Path::new(arg) + .file_name() + .and_then(|name| name.to_str()) + .is_some_and(|name| matches!(name, "dart" | "dart.exe")) + } + + fn has_packages_arg(arg: &str) -> bool { + arg == "-p" || arg == "--packages" || arg.starts_with("--packages=") + } + + fn is_dart_script(arg: &str) -> bool { + Path::new(arg) + .extension() + .is_some_and(|ext| ext.eq_ignore_ascii_case("dart")) + } + + let dart_index = entry.iter().position(|arg| is_dart_binary(arg))?; + + for (index, arg) in entry + .iter() + .chain(hook_args) + .enumerate() + .skip(dart_index + 1) + { + // Respect an explicit package config only while still parsing Dart VM + // options. After `run` or a script target, this may be a hook argument. + if has_packages_arg(arg) { + return None; + } + + if !arg.starts_with('-') { + // `--packages` is a VM flag, so place it before `run` or a script target. + if arg != "run" && !is_dart_script(arg) { + return None; + } + return Some(index.min(entry.len())); + } + } + + None +} + +/// Compile declared package executables into the hook env's `bin` directory. +async fn compile_executables( + dart: &Path, + source_path: &Path, + bin_dir: &Path, + packages_path: &Path, + executables: BTreeMap, +) -> Result<()> { + if executables.is_empty() { + return Ok(()); + } + + fs_err::create_dir_all(bin_dir)?; + + for (output_name, executable) in executables { + let entrypoint = executable.into_entrypoint(&output_name); + let mut relative_entrypoint = PathBuf::from(&entrypoint); + if relative_entrypoint.extension().is_none() { + relative_entrypoint.set_extension("dart"); + } + let source_file = source_path.join("bin").join(relative_entrypoint); + if !source_file.exists() { + debug!("Skipping executable `{output_name}`: source file not found"); + continue; + } + + let output_path = bin_dir.join(&output_name).with_extension(EXE_EXTENSION); + + debug!( + "Compiling executable `{output_name}`: {source} -> {output}", + source = source_file.display(), + output = output_path.display(), + ); + + Cmd::new(dart, "dart compile exe") + .arg("compile") + .arg("exe") + .arg(format!("--packages={}", packages_path.display())) + .arg(&source_file) + .arg("--output") + .arg(&output_path) + .check(true) + .output() + .await?; + } + + Ok(()) +} + +/// Build the synthetic pubspec used to resolve the hook's Dart dependencies. +fn build_env_pubspec( + source_path: Option<&Path>, + package_name: Option<&str>, + dependencies: &rustc_hash::FxHashSet, +) -> Pubspec { + let mut resolved_dependencies = BTreeMap::new(); + + let mut dependencies = dependencies.iter().collect::>(); + dependencies.sort_unstable(); + + for dep in dependencies { + if let Some((package, version)) = dep.split_once(':') { + resolved_dependencies.insert( + package.to_string(), + PubspecDependency::Version(version.to_string()), + ); + } else { + resolved_dependencies + .insert(dep.clone(), PubspecDependency::Version("any".to_string())); + } + } + + if let (Some(source_path), Some(package_name)) = (source_path, package_name) { + resolved_dependencies.insert( + package_name.to_string(), + PubspecDependency::Path { + path: source_path.to_path_buf(), + }, + ); + } + + Pubspec { + name: "prek_dart_env".to_string(), + environment: BTreeMap::from([("sdk".to_string(), ">=2.12.0 <4.0.0".to_string())]), + dependencies: resolved_dependencies, + executables: BTreeMap::new(), + } +} + +/// Write the synthetic pubspec and resolve it into a package config. +async fn install_package_config( + dart: &Path, + env_path: &Path, + source_path: Option<&Path>, + package_name: Option<&str>, + dependencies: &rustc_hash::FxHashSet, +) -> Result<()> { + let pubspec = build_env_pubspec(source_path, package_name, dependencies); + let pubspec_content = serde_saphyr::to_string(&pubspec)?; + let pubspec_path = env_path.join(PUBSPEC_YAML); + fs_err::tokio::write(&pubspec_path, pubspec_content).await?; + + Cmd::new(dart, "dart pub get") + .current_dir(env_path) + .env(EnvVars::PUB_CACHE, env_path) + .arg("pub") + .arg("get") + .check(true) + .output() + .await?; + + Ok(()) +} + +/// Install a local Dart package hook and compile its declared executables. +async fn install_from_pubspec( + dart: &Path, + env_path: &Path, + source_path: &Path, + dependencies: &rustc_hash::FxHashSet, +) -> Result<()> { + let pubspec_path = source_path.join(PUBSPEC_YAML); + let pubspec_content = fs_err::read_to_string(&pubspec_path)?; + let pubspec: Pubspec = serde_saphyr::from_str(&pubspec_content)?; + + install_package_config( + dart, + env_path, + Some(source_path), + Some(&pubspec.name), + dependencies, + ) + .await + .context("Failed to install Dart pubspec dependencies")?; + + compile_executables( + dart, + source_path, + &bin_path(env_path), + &package_config_path(env_path), + pubspec.executables, + ) + .await + .context("Failed to compile Dart pubspec executables")?; + + Ok(()) +} + +#[cfg(test)] +mod tests { + use super::*; + use anyhow::Result; + + fn strings(values: &[&str]) -> Vec { + values.iter().map(ToString::to_string).collect() + } + + #[test] + fn packages_arg_insert_position_inserts_before_dart_run() { + let entry = strings(&["/usr/bin/dart", "run", "bin/hook.dart"]); + + assert_eq!(packages_arg_insert_position(&entry, &[]), Some(1)); + } + + #[test] + fn packages_arg_insert_position_keeps_existing_packages_arg() { + assert_eq!( + packages_arg_insert_position(&strings(&["dart", "--packages=custom", "run"]), &[]), + None + ); + assert_eq!( + packages_arg_insert_position(&strings(&["dart", "--packages", "custom", "run"]), &[]), + None + ); + assert_eq!( + packages_arg_insert_position( + &strings(&["dart"]), + &strings(&["--packages=custom", "run"]) + ), + None + ); + } + + #[test] + fn packages_arg_insert_position_only_checks_vm_options_for_packages_arg() { + assert_eq!( + packages_arg_insert_position(&strings(&["dart", "run", "tool.dart", "-p"]), &[]), + Some(1) + ); + assert_eq!( + packages_arg_insert_position( + &strings(&["dart", "tool.dart", "--packages=script-value"]), + &[] + ), + Some(1) + ); + assert_eq!( + packages_arg_insert_position( + &strings(&["dart"]), + &strings(&["run", "tool.dart", "--packages=script-value"]) + ), + Some(1) + ); + } + + #[test] + fn packages_arg_insert_position_checks_hook_args() { + assert_eq!( + packages_arg_insert_position(&strings(&["dart"]), &strings(&["run", "bin/hook.dart"])), + Some(1) + ); + assert_eq!( + packages_arg_insert_position(&strings(&["dart"]), &strings(&["bin/hook.dart"])), + Some(1) + ); + assert_eq!( + packages_arg_insert_position( + &strings(&["dart", "--enable-asserts"]), + &strings(&["run", "bin/hook.dart"]) + ), + Some(2) + ); + } + + #[test] + fn build_env_pubspec_serializes_path_dependency() -> Result<()> { + let temp_dir = tempfile::tempdir()?; + let dependencies = rustc_hash::FxHashSet::default(); + + let pubspec = build_env_pubspec(Some(temp_dir.path()), Some("sample"), &dependencies); + + match pubspec.dependencies.get("sample") { + Some(PubspecDependency::Path { path }) => assert_eq!(path, temp_dir.path()), + dependency => panic!("expected path dependency, got {dependency:?}"), + } + + Ok(()) + } + + #[test] + fn pubspec_deserialization_ignores_unread_fields() -> Result<()> { + let pubspec: Pubspec = serde_saphyr::from_str(indoc::indoc! {r" + name: sample + environment: + sdk: '>=2.17.0 <4.0.0' + dependencies: + hosted_dep: + hosted: https://pub.dev + version: ^1.0.0 + sdk_dep: + sdk: flutter + executables: + sample: + "})?; + + assert_eq!(pubspec.name, "sample"); + assert!(pubspec.environment.is_empty()); + assert!(pubspec.dependencies.is_empty()); + assert!(pubspec.executables.contains_key("sample")); + + Ok(()) + } +} diff --git a/crates/prek/src/languages/mod.rs b/crates/prek/src/languages/mod.rs index f936783f1..4270dd11d 100644 --- a/crates/prek/src/languages/mod.rs +++ b/crates/prek/src/languages/mod.rs @@ -16,6 +16,7 @@ use crate::hooks; use crate::store::{CacheBucket, Store, ToolBucket}; mod bun; +mod dart; mod deno; mod docker; mod docker_image; @@ -36,6 +37,7 @@ mod system; pub(crate) mod version; static BUN: bun::Bun = bun::Bun; +static DART: dart::Dart = dart::Dart; static DENO: deno::Deno = deno::Deno; static DOCKER: docker::Docker = docker::Docker; static DOCKER_IMAGE: docker_image::DockerImage = docker_image::DockerImage; @@ -138,6 +140,7 @@ impl Language { pub(crate) fn supported(lang: Language) -> bool { match lang { Self::Bun + | Self::Dart | Self::Deno | Self::Docker | Self::DockerImage @@ -155,7 +158,7 @@ impl Language { | Self::Script | Self::Swift | Self::System => true, - Self::Conda | Self::Coursier | Self::Dart | Self::Perl | Self::R => false, + Self::Conda | Self::Coursier | Self::Perl | Self::R => false, } } @@ -198,9 +201,12 @@ impl Language { | Self::Script | Self::Swift | Self::System => ShellSupport::Supported, - Self::Conda | Self::Coursier | Self::Dart | Self::Perl | Self::R => { + Self::Conda | Self::Coursier | Self::Perl | Self::R => { ShellSupport::Unsupported("no runner is implemented yet") } + Self::Dart => ShellSupport::Unsupported( + "`--packages` injection requires the resolved argv to contain `dart` directly", + ), Self::Docker | Self::DockerImage => ShellSupport::Unsupported( "`entry` participates in container image or entrypoint selection", ), @@ -336,6 +342,7 @@ impl Language { reporter: &HookInstallReporter, ) -> Result { match self { + Self::Dart => DART.install(hook, store, reporter).await, Self::Bun => BUN.install(hook, store, reporter).await, Self::Deno => DENO.install(hook, store, reporter).await, Self::Docker => DOCKER.install(hook, store, reporter).await, @@ -354,7 +361,7 @@ impl Language { Self::Script => SCRIPT.install(hook, store, reporter).await, Self::Swift => SWIFT.install(hook, store, reporter).await, Self::System => SYSTEM.install(hook, store, reporter).await, - Self::Conda | Self::Coursier | Self::Dart | Self::Perl | Self::R => { + Self::Conda | Self::Coursier | Self::Perl | Self::R => { UNIMPLEMENTED.install(hook, store, reporter).await } } @@ -362,6 +369,7 @@ impl Language { pub(crate) async fn check_health(&self, info: &InstallInfo) -> Result<()> { match self { + Self::Dart => DART.check_health(info).await, Self::Bun => BUN.check_health(info).await, Self::Deno => DENO.check_health(info).await, Self::Docker => DOCKER.check_health(info).await, @@ -380,7 +388,7 @@ impl Language { Self::Script => SCRIPT.check_health(info).await, Self::Swift => SWIFT.check_health(info).await, Self::System => SYSTEM.check_health(info).await, - Self::Conda | Self::Coursier | Self::Dart | Self::Perl | Self::R => { + Self::Conda | Self::Coursier | Self::Perl | Self::R => { UNIMPLEMENTED.check_health(info).await } } @@ -417,6 +425,7 @@ impl Language { } match self { + Self::Dart => DART.run(hook, filenames, store, reporter).await, Self::Bun => BUN.run(hook, filenames, store, reporter).await, Self::Deno => DENO.run(hook, filenames, store, reporter).await, Self::Docker => DOCKER.run(hook, filenames, store, reporter).await, @@ -435,7 +444,7 @@ impl Language { Self::Script => SCRIPT.run(hook, filenames, store, reporter).await, Self::Swift => SWIFT.run(hook, filenames, store, reporter).await, Self::System => SYSTEM.run(hook, filenames, store, reporter).await, - Self::Conda | Self::Coursier | Self::Dart | Self::Perl | Self::R => { + Self::Conda | Self::Coursier | Self::Perl | Self::R => { UNIMPLEMENTED.run(hook, filenames, store, reporter).await } } diff --git a/crates/prek/tests/languages/dart.rs b/crates/prek/tests/languages/dart.rs new file mode 100644 index 000000000..4336c9750 --- /dev/null +++ b/crates/prek/tests/languages/dart.rs @@ -0,0 +1,575 @@ +use assert_fs::fixture::{FileWriteStr, PathChild}; + +use crate::common::{TestContext, cmd_snapshot}; + +#[test] +fn language_version() { + let context = TestContext::new(); + context.init_project(); + context.write_pre_commit_config(indoc::indoc! {r" + repos: + - repo: local + hooks: + - id: local + name: local + language: dart + entry: dart --version + language_version: '3.0' + always_run: true + verbose: true + pass_filenames: false + "}); + + context.git_add("."); + + cmd_snapshot!(context.filters(), context.run(), @r" + success: false + exit_code: 2 + ----- stdout ----- + + ----- stderr ----- + error: Failed to init hooks + caused by: Invalid hook `local` + caused by: Hook specified `language_version: 3.0` but the language `dart` does not support toolchain installation for now + "); +} + +#[test] +fn hook_stderr() -> anyhow::Result<()> { + let context = TestContext::new(); + context.init_project(); + + context.write_pre_commit_config(indoc::indoc! {r" + repos: + - repo: local + hooks: + - id: local + name: local + language: dart + entry: dart ./hook.dart + "}); + + context + .work_dir() + .child("hook.dart") + .write_str(indoc::indoc! {r" + import 'dart:io'; + void main() { + stderr.writeln('Error from Dart hook'); + exit(1); + } + "})?; + + context.git_add("."); + + cmd_snapshot!(context.filters(), context.run(), @r" + success: false + exit_code: 1 + ----- stdout ----- + local....................................................................Failed + - hook id: local + - exit code: 1 + + Error from Dart hook + + ----- stderr ----- + "); + + Ok(()) +} + +#[test] +fn script_with_files() -> anyhow::Result<()> { + let context = TestContext::new(); + context.init_project(); + + context.write_pre_commit_config(indoc::indoc! {r" + repos: + - repo: local + hooks: + - id: dart + name: dart + language: dart + entry: dart ./script.dart + verbose: true + "}); + + context + .work_dir() + .child("script.dart") + .write_str(indoc::indoc! {r" + import 'dart:io'; + void main(List args) { + for (var arg in args) { + print('Processing file: $arg'); + } + } + "})?; + + context + .work_dir() + .child("test1.dart") + .write_str("void main() { print('test1'); }")?; + + context + .work_dir() + .child("test2.dart") + .write_str("void main() { print('test2'); }")?; + + context.git_add("."); + + cmd_snapshot!(context.filters(), context.run(), @r" + success: true + exit_code: 0 + ----- stdout ----- + dart.....................................................................Passed + - hook id: dart + - duration: [TIME] + + Processing file: script.dart + Processing file: .pre-commit-config.yaml + Processing file: test2.dart + Processing file: test1.dart + + ----- stderr ----- + "); + + Ok(()) +} + +#[test] +fn with_pubspec_and_dependencies() -> anyhow::Result<()> { + let context = TestContext::new(); + context.init_project(); + + context.write_pre_commit_config(indoc::indoc! {r" + repos: + - repo: local + hooks: + - id: dart + name: dart + language: dart + entry: hello-world-dart + always_run: true + verbose: true + pass_filenames: false + "}); + + context + .work_dir() + .child("pubspec.yaml") + .write_str(indoc::indoc! {r" + environment: + sdk: '>=2.17.0 <4.0.0' + + name: hello_world_dart + + executables: + hello-world-dart: + + dependencies: + ansicolor: ^2.0.1 + "})?; + + std::fs::create_dir(context.work_dir().join("bin"))?; + context + .work_dir() + .child("bin") + .child("hello-world-dart.dart") + .write_str(indoc::indoc! {r#" + import 'package:ansicolor/ansicolor.dart'; + + void main() { + AnsiPen pen = new AnsiPen()..red(); + print("hello hello " + pen("world")); + } + "#})?; + + context.git_add("."); + + cmd_snapshot!(context.filters(), context.run(), @r" + success: true + exit_code: 0 + ----- stdout ----- + dart.....................................................................Passed + - hook id: dart + - duration: [TIME] + + hello hello world + + ----- stderr ----- + "); + + Ok(()) +} + +#[test] +fn with_pubspec() -> anyhow::Result<()> { + let context = TestContext::new(); + context.init_project(); + + context.write_pre_commit_config(indoc::indoc! {r" + repos: + - repo: local + hooks: + - id: dart + name: dart + language: dart + entry: dart ./bin/hello.dart + always_run: true + verbose: true + pass_filenames: false + "}); + + context + .work_dir() + .child("pubspec.yaml") + .write_str(indoc::indoc! {r" + name: test_package + description: A test package + version: 1.0.0 + environment: + sdk: '>=2.17.0 <4.0.0' + "})?; + + std::fs::create_dir(context.work_dir().join("bin"))?; + context + .work_dir() + .child("bin") + .child("hello.dart") + .write_str(indoc::indoc! {r" + void main() { + print('Hello from Dart package!'); + } + "})?; + + context.git_add("."); + + cmd_snapshot!(context.filters(), context.run(), @r" + success: true + exit_code: 0 + ----- stdout ----- + dart.....................................................................Passed + - hook id: dart + - duration: [TIME] + + Hello from Dart package! + + ----- stderr ----- + "); + + assert!( + !context.work_dir().path().join(".dart_tool").exists(), + "Dart hooks should not mutate the checkout with .dart_tool" + ); + + Ok(()) +} + +#[test] +fn with_pubspec_and_additional_dependencies() -> anyhow::Result<()> { + let context = TestContext::new(); + context.init_project(); + + context.write_pre_commit_config(indoc::indoc! {r#" + repos: + - repo: local + hooks: + - id: dart + name: dart + language: dart + entry: dart ./bin/hello.dart + additional_dependencies: ["path"] + always_run: true + verbose: true + pass_filenames: false + "#}); + + context + .work_dir() + .child("pubspec.yaml") + .write_str(indoc::indoc! {r" + name: test_package + description: A test package + version: 1.0.0 + environment: + sdk: '>=2.17.0 <4.0.0' + "})?; + + std::fs::create_dir(context.work_dir().join("bin"))?; + std::fs::create_dir(context.work_dir().join("lib"))?; + context + .work_dir() + .child("lib") + .child("greeting.dart") + .write_str(indoc::indoc! {r" + String greet(String subject) => 'Hello $subject!'; + "})?; + context + .work_dir() + .child("bin") + .child("hello.dart") + .write_str(indoc::indoc! {r" + import 'package:path/path.dart' as p; + import 'package:test_package/greeting.dart'; + + void main() { + print(greet(p.posix.join('Dart', 'Hooks'))); + } + "})?; + + context.git_add("."); + + cmd_snapshot!(context.filters(), context.run(), @r" + success: true + exit_code: 0 + ----- stdout ----- + dart.....................................................................Passed + - hook id: dart + - duration: [TIME] + + Hello Dart/Hooks! + + ----- stderr ----- + "); + + assert!( + !context.work_dir().path().join(".dart_tool").exists(), + "Dart hooks should not mutate the checkout with .dart_tool" + ); + + Ok(()) +} + +#[test] +fn additional_dependencies() { + let context = TestContext::new(); + context.init_project(); + + context.write_pre_commit_config(indoc::indoc! {r#" + repos: + - repo: local + hooks: + - id: dart + name: dart + language: dart + entry: dart ./test_path.dart + additional_dependencies: ["path"] + always_run: true + verbose: true + pass_filenames: false + "#}); + + context + .work_dir() + .child("test_path.dart") + .write_str(indoc::indoc! {r" + import 'package:path/path.dart' as p; + void main() { + var joined = p.join('foo', 'bar', 'baz.txt'); + print('Joined path: $joined'); + } + "}) + .unwrap(); + + context.git_add("."); + + cmd_snapshot!(context.filters(), context.run(), @r" + success: true + exit_code: 0 + ----- stdout ----- + dart.....................................................................Passed + - hook id: dart + - duration: [TIME] + + Joined path: foo/bar/baz.txt + + ----- stderr ----- + "); +} + +#[test] +fn additional_dependencies_with_version() { + let context = TestContext::new(); + context.init_project(); + + context.write_pre_commit_config(indoc::indoc! {r#" + repos: + - repo: local + hooks: + - id: dart + name: dart + language: dart + entry: dart ./test_path.dart + additional_dependencies: ["path:1.8.0"] + always_run: true + verbose: true + pass_filenames: false + "#}); + + context + .work_dir() + .child("test_path.dart") + .write_str(indoc::indoc! {r" + import 'package:path/path.dart' as p; + void main() { + print('Using path package'); + } + "}) + .unwrap(); + + context.git_add("."); + + cmd_snapshot!(context.filters(), context.run(), @r" + success: true + exit_code: 0 + ----- stdout ----- + dart.....................................................................Passed + - hook id: dart + - duration: [TIME] + + Using path package + + ----- stderr ----- + "); +} + +#[test] +fn executable_alias() -> anyhow::Result<()> { + let context = TestContext::new(); + context.init_project(); + + context.write_pre_commit_config(indoc::indoc! {r" + repos: + - repo: local + hooks: + - id: dart + name: dart + language: dart + entry: cli + always_run: true + verbose: true + pass_filenames: false + "}); + + context + .work_dir() + .child("pubspec.yaml") + .write_str(indoc::indoc! {r" + name: aliased_dart_tool + environment: + sdk: '>=2.17.0 <4.0.0' + + executables: + cli: hello + "})?; + + std::fs::create_dir(context.work_dir().join("bin"))?; + context + .work_dir() + .child("bin") + .child("hello.dart") + .write_str(indoc::indoc! {r" + void main() { + print('alias executable works'); + } + "})?; + + context.git_add("."); + + cmd_snapshot!(context.filters(), context.run(), @r" + success: true + exit_code: 0 + ----- stdout ----- + dart.....................................................................Passed + - hook id: dart + - duration: [TIME] + + alias executable works + + ----- stderr ----- + "); + + Ok(()) +} + +#[test] +fn dart_environment() { + let context = TestContext::new(); + context.init_project(); + + context.write_pre_commit_config(indoc::indoc! {r" + repos: + - repo: local + hooks: + - id: dart + name: dart + language: dart + entry: dart ./env_test.dart + always_run: true + verbose: true + pass_filenames: false + "}); + + context + .work_dir() + .child("env_test.dart") + .write_str(indoc::indoc! {r" + import 'dart:io'; + void main() { + var pubCache = Platform.environment['PUB_CACHE']; + if (pubCache != null) { + print('PUB_CACHE is set: ${pubCache.isNotEmpty}'); + } else { + print('PUB_CACHE is not set'); + } + } + "}) + .unwrap(); + + context.git_add("."); + + cmd_snapshot!(context.filters(), context.run(), @r" + success: true + exit_code: 0 + ----- stdout ----- + dart.....................................................................Passed + - hook id: dart + - duration: [TIME] + + PUB_CACHE is set: true + + ----- stderr ----- + "); +} + +#[test] +fn remote_hook() { + let context = TestContext::new(); + context.init_project(); + + context.write_pre_commit_config(indoc::indoc! {r" + repos: + - repo: https://github.com/prek-test-repos/dart-hooks + rev: v1.1.0 + hooks: + - id: dart-hooks + always_run: true + verbose: true + "}); + + context.git_add("."); + + cmd_snapshot!(context.filters(), context.run(), @r" + success: true + exit_code: 0 + ----- stdout ----- + dart-hooks...............................................................Passed + - hook id: dart-hooks + - duration: [TIME] + + this is a dart remote hook + + ----- stderr ----- + "); +} diff --git a/crates/prek/tests/languages/main.rs b/crates/prek/tests/languages/main.rs index 422088ac6..0cdfbf13e 100644 --- a/crates/prek/tests/languages/main.rs +++ b/crates/prek/tests/languages/main.rs @@ -2,6 +2,7 @@ mod common; mod bun; +mod dart; mod deno; #[cfg(all(feature = "docker", target_os = "linux"))] mod docker; diff --git a/docs/languages.md b/docs/languages.md index be293f85e..67660a5da 100644 --- a/docs/languages.md +++ b/docs/languages.md @@ -78,9 +78,61 @@ Tracking: [#53](https://github.com/j178/prek/issues/53) ### dart -**Status in prek:** Not supported yet. +**Status in prek:** ✅ Supported. + +prek runs Dart hooks with a system-installed `dart` executable. + +Dart hooks can run plain Dart commands, repository scripts, or package +executables: + +- `entry: dart --version` +- `entry: dart ./tool/hook.dart` +- `entry: dart run bin/hook.dart` +- `entry: my-package-executable` + +If the hook repository contains `pubspec.yaml`, prek uses it to resolve package +dependencies and declared executables. `additional_dependencies` are supported +for both package hooks and standalone Dart scripts. + +#### `pubspec.yaml` executables + +For package hooks, executables declared in `pubspec.yaml` can be used as hook +entries. The executable key is the command name: + +```yaml +name: my_dart_hooks + +executables: + my-hook: + aliased-hook: tool/main +``` + +`my-hook` resolves to `bin/my-hook.dart`. `aliased-hook` resolves to +`bin/tool/main.dart`. Empty or null executable values use the executable key as +the entrypoint name, matching Dart's pub behavior. + +#### `additional_dependencies` + +Use `package` for the latest compatible version or `package:version` to pin a +version: + +```yaml +repos: + - repo: local + hooks: + - id: dart-hook + name: Dart hook + language: dart + entry: dart ./bin/hook.dart + additional_dependencies: + - path + - args:2.7.0 +``` + +#### `language_version` -Tracking: [#51](https://github.com/j178/prek/issues/51) +Dart does not support managed toolchain installation today. It uses the system +`dart` executable, and explicit Dart version requests are rejected. ### docker diff --git a/docs/proposals/hook-shell.md b/docs/proposals/hook-shell.md index 4ee2493c0..0917404bf 100644 --- a/docs/proposals/hook-shell.md +++ b/docs/proposals/hook-shell.md @@ -167,10 +167,11 @@ the hook command on the host. | Language | Why `shell` is unsupported | | -- | -- | | `docker`, `docker_image` | `entry` participates in container image or entrypoint selection instead of direct host process execution. | + | `dart` | Dart package config injection requires `entry` to resolve to a direct `dart` command. | | `fail` | `entry` is the failure message body. | | `julia`, `rust` | `entry` participates in install/runtime package resolution and is split before execution. | | `pygrep` | `entry` is the regex pattern. | - | `conda`, `coursier`, `dart`, `perl`, `r` | The language backend is not implemented yet. | + | `conda`, `coursier`, `perl`, `r` | The language backend is not implemented yet. | Predefined `repo: meta` and `repo: builtin` hooks should reject `shell` as well, because their entries are owned by prek. diff --git a/docs/reference/configuration.md b/docs/reference/configuration.md index 4badf2c6b..694d43875 100644 --- a/docs/reference/configuration.md +++ b/docs/reference/configuration.md @@ -648,10 +648,11 @@ When `shell` is set, `entry` is treated as source for that shell. `prek` writes | Language | Why `shell` is unsupported | | -- | -- | | `docker`, `docker_image` | `entry` participates in container image or entrypoint selection instead of direct host process execution. | + | `dart` | Dart package config injection requires `entry` to resolve to a direct `dart` command. | | `fail` | `entry` is the failure message body. | | `julia`, `rust` | `entry` participates in install/runtime package resolution and is split before execution. | | `pygrep` | `entry` is the regex pattern. | - | `conda`, `coursier`, `dart`, `perl`, `r` | The language backend is not implemented yet. | + | `conda`, `coursier`, `perl`, `r` | The language backend is not implemented yet. | ### `language` From 5770b92551bcfd28b5faf3c776e40232cd63b666 Mon Sep 17 00:00:00 2001 From: Jo <10510431+j178@users.noreply.github.com> Date: Sun, 3 May 2026 14:23:50 +0800 Subject: [PATCH 10/23] Generate CI language tests matrix (#2029) Generate the language-test matrix and core nextest filter from a Python script so the grouping size and language deny-list stay in one place. --- .config/nextest.toml | 4 -- .github/workflows/ci.yml | 75 +++++--------------- scripts/generate_ci_matrix.py | 126 ++++++++++++++++++++++++++++++++++ 3 files changed, 143 insertions(+), 62 deletions(-) create mode 100644 scripts/generate_ci_matrix.py diff --git a/.config/nextest.toml b/.config/nextest.toml index 800d2fd2d..bb718ec7d 100644 --- a/.config/nextest.toml +++ b/.config/nextest.toml @@ -1,8 +1,4 @@ [profile.ci-core] -# Exclude heavy language-specific integration tests from the main CI runs. -# Keep this as a deny-list so new language test modules run in ci-core until -# they are deliberately moved to the language-test matrix. -default-filter = "not binary_id(prek::languages) or (binary_id(prek::languages) and not (test(bun::) or test(dart::) or test(deno::) or test(docker::) or test(docker_image::) or test(dotnet::) or test(golang::) or test(haskell::) or test(julia::) or test(lua::) or test(node::) or test(python::) or test(ruby::) or test(rust::) or test(swift::)))" status-level = "skip" final-status-level = "slow" failure-output = "immediate" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 06a984405..4e7be7a6b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -42,6 +42,8 @@ jobs: outputs: test-code: ${{ !contains(github.event.pull_request.labels.*.name, 'test:skip') && (steps.changed.outputs.any_code_changed == 'true' || github.ref == 'refs/heads/master') }} save-rust-cache: ${{ github.ref == 'refs/heads/master' || steps.changed.outputs.cache_changed == 'true' }} + language-test-matrix: ${{ steps.nextest.outputs.language-test-matrix }} + ci-core-filter: ${{ steps.nextest.outputs.ci-core-filter }} # Run benchmarks if Rust code or benchmark-related files changed run-bench: ${{ !contains(github.event.pull_request.labels.*.name, 'test:skip') && (steps.changed.outputs.rust_code_changed == 'true' || steps.changed.outputs.bench_related_changed == 'true' || github.ref == 'refs/heads/master') }} steps: @@ -103,6 +105,12 @@ jobs: echo "bench_related_changed=${BENCH_RELATED_CHANGED}" } >> "${GITHUB_OUTPUT}" + - name: "Generate nextest filters" + id: nextest + shell: bash + run: | + python3 scripts/generate_ci_matrix.py --group-size 4 --github-output >> "${GITHUB_OUTPUT}" + lint: name: "lint" timeout-minutes: 10 @@ -312,6 +320,8 @@ jobs: python-version: ${{ env.PYTHON_VERSION }} - name: "Cargo test" + env: + CI_CORE_FILTER: ${{ needs.plan.outputs.ci-core-filter }} run: | cargo llvm-cov nextest \ --lcov \ @@ -319,7 +329,8 @@ jobs: --workspace \ --cargo-profile fast-build \ --profile ci-core \ - --features schemars + --features schemars \ + -E "${CI_CORE_FILTER}" - name: "Upload coverage reports to Codecov" uses: codecov/codecov-action@57e3a136b779b570ffcdbf80b3bdc90e7fab3de2 # v6.0.0 @@ -380,6 +391,8 @@ jobs: - name: "Cargo test" working-directory: ${{ env.PREK_WORKSPACE }} shell: pwsh + env: + CI_CORE_FILTER: ${{ needs.plan.outputs.ci-core-filter }} run: | # Remove msys64 from PATH for Rust compilation $env:PATH = ($env:PATH -split ';' | Where-Object { $_ -notmatch '\\msys64\\' }) -join ';' @@ -390,7 +403,8 @@ jobs: --workspace ` --cargo-profile fast-build ` --features schemars ` - --profile ci-core + --profile ci-core ` + -E $env:CI_CORE_FILTER if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } @@ -408,62 +422,7 @@ jobs: runs-on: ${{ matrix.os }} strategy: fail-fast: false - matrix: - # Keep platform constraints encoded directly in grouped rows: - # Docker only runs on Ubuntu, Swift skips Windows, and Haskell skips macOS. - include: - - os: ubuntu-latest - group: 1 - languages: bun dart deno - filter: test(bun::) or test(dart::) or test(deno::) - - os: ubuntu-latest - group: 2 - languages: docker dotnet golang - filter: test(docker::) or test(docker_image::) or test(dotnet::) or test(golang::) - - os: ubuntu-latest - group: 3 - languages: haskell julia lua - filter: test(haskell::) or test(julia::) or test(lua::) - - os: ubuntu-latest - group: 4 - languages: node python ruby - filter: test(node::) or test(python::) or test(ruby::) - - os: ubuntu-latest - group: 5 - languages: rust swift - filter: test(rust::) or test(swift::) - - os: macos-latest - group: 1 - languages: bun dart deno - filter: test(bun::) or test(dart::) or test(deno::) - - os: macos-latest - group: 2 - languages: dotnet golang julia - filter: test(dotnet::) or test(golang::) or test(julia::) - - os: macos-latest - group: 3 - languages: lua node python - filter: test(lua::) or test(node::) or test(python::) - - os: macos-latest - group: 4 - languages: ruby rust swift - filter: test(ruby::) or test(rust::) or test(swift::) - - os: windows-latest - group: 1 - languages: bun dart deno - filter: test(bun::) or test(dart::) or test(deno::) - - os: windows-latest - group: 2 - languages: dotnet golang haskell - filter: test(dotnet::) or test(golang::) or test(haskell::) - - os: windows-latest - group: 3 - languages: julia lua node - filter: test(julia::) or test(lua::) or test(node::) - - os: windows-latest - group: 4 - languages: python ruby rust - filter: test(python::) or test(ruby::) or test(rust::) + matrix: ${{ fromJSON(needs.plan.outputs.language-test-matrix) }} steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: diff --git a/scripts/generate_ci_matrix.py b/scripts/generate_ci_matrix.py new file mode 100644 index 000000000..c697a4cd4 --- /dev/null +++ b/scripts/generate_ci_matrix.py @@ -0,0 +1,126 @@ +# /// script +# requires-python = ">=3.11" +# /// + +from __future__ import annotations + +import argparse +import json +from dataclasses import dataclass + +LANGUAGE_FILTERS = { + "bun": "test(bun::)", + "dart": "test(dart::)", + "deno": "test(deno::)", + "docker": "test(docker::) or test(docker_image::)", + "dotnet": "test(dotnet::)", + "golang": "test(golang::)", + "haskell": "test(haskell::)", + "julia": "test(julia::)", + "lua": "test(lua::)", + "node": "test(node::)", + "python": "test(python::)", + "ruby": "test(ruby::)", + "rust": "test(rust::)", + "swift": "test(swift::)", +} + +LANGUAGES = tuple(LANGUAGE_FILTERS) + + +@dataclass(frozen=True) +class Platform: + os: str + unsupported_languages: frozenset[str] + + def languages(self) -> list[str]: + return [ + language + for language in LANGUAGES + if language not in self.unsupported_languages + ] + + +PLATFORMS = ( + # Docker only runs on Ubuntu, Swift skips Windows, and Haskell skips macOS. + Platform("ubuntu-latest", frozenset()), + Platform("macos-latest", frozenset({"docker", "haskell"})), + Platform("windows-latest", frozenset({"docker", "swift"})), +) + + +def chunks(items: list[str], size: int) -> list[list[str]]: + return [items[index : index + size] for index in range(0, len(items), size)] + + +def language_filter(languages: list[str]) -> str: + return " or ".join(LANGUAGE_FILTERS[language] for language in languages) + + +def ci_core_filter() -> str: + # Exclude heavy language-specific integration tests from the main CI runs. + excluded_languages = language_filter(list(LANGUAGES)) + + # Keep this as a deny-list so new language test modules run in ci-core until + # they are deliberately added to LANGUAGE_FILTERS and the language-test matrix. + return ( + "not binary_id(prek::languages) or " + f"(binary_id(prek::languages) and not ({excluded_languages}))" + ) + + +def generate_language_test_matrix(group_size: int) -> dict[str, list[dict[str, str | int]]]: + include = [] + for platform in PLATFORMS: + for group, languages in enumerate(chunks(platform.languages(), group_size), start=1): + include.append( + { + "os": platform.os, + "group": group, + "languages": " ".join(languages), + "filter": language_filter(languages), + } + ) + + return {"include": include} + + +def parse_args() -> argparse.Namespace: + parser = argparse.ArgumentParser( + description="Generate GitHub Actions matrices for CI jobs.", + ) + parser.add_argument( + "--group-size", + type=int, + default=4, + help="maximum number of languages per language-test job", + ) + parser.add_argument( + "--github-output", + action="store_true", + help="emit values in GitHub Actions output format", + ) + return parser.parse_args() + + +def main() -> None: + args = parse_args() + if args.group_size < 1: + msg = "--group-size must be greater than zero" + raise SystemExit(msg) + + language_test_matrix = json.dumps( + generate_language_test_matrix(args.group_size), + separators=(",", ":"), + ) + core_filter = ci_core_filter() + + if args.github_output: + print(f"language-test-matrix={language_test_matrix}") + print(f"ci-core-filter={core_filter}") + else: + print(language_test_matrix) + + +if __name__ == "__main__": + main() From a01ff4d05b9e9284545e4e674381f7ced2d34421 Mon Sep 17 00:00:00 2001 From: Jo <10510431+j178@users.noreply.github.com> Date: Sun, 3 May 2026 16:17:48 +0800 Subject: [PATCH 11/23] Centralize CI workflow planning (#2030) --- .github/workflows/build-dev-binaries.yml | 135 +++++++++ .github/workflows/build-docker.yml | 36 ++- ...inaries.yml => build-release-binaries.yml} | 14 +- .github/workflows/ci.yml | 285 ++++++++---------- .github/workflows/release.yml | 10 +- .github/workflows/zizmor.yml | 6 +- dist-workspace.toml | 2 +- 7 files changed, 293 insertions(+), 195 deletions(-) create mode 100644 .github/workflows/build-dev-binaries.yml rename .github/workflows/{build-binaries.yml => build-release-binaries.yml} (98%) diff --git a/.github/workflows/build-dev-binaries.yml b/.github/workflows/build-dev-binaries.yml new file mode 100644 index 000000000..76871b2b2 --- /dev/null +++ b/.github/workflows/build-dev-binaries.yml @@ -0,0 +1,135 @@ +name: "Build dev binaries" + +on: + workflow_call: + inputs: + save-rust-cache: + required: false + type: string + default: "true" + +permissions: {} + +env: + CARGO_INCREMENTAL: 0 + CARGO_NET_RETRY: 10 + CARGO_TERM_COLOR: always + RUSTUP_MAX_RETRIES: 10 + +jobs: + build-binary-msrv: + name: "build binary | msrv" + runs-on: ubuntu-latest + timeout-minutes: 10 + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false + + - name: "Read MSRV from Cargo.toml" + id: msrv + run: | + MSRV=$(grep -m1 'rust-version' Cargo.toml | sed 's/.*"\([^"]*\)".*/\1/') + echo "value=$MSRV" >> "$GITHUB_OUTPUT" + + - name: "Install Rust toolchain" + run: rustup default "${MSRV}" + env: + MSRV: ${{ steps.msrv.outputs.value }} + + - name: "Install mold" + uses: rui314/setup-mold@9c9c13bf4c3f1adef0cc596abc155580bcb04444 # v1 + + - uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1 + with: + save-if: ${{ inputs.save-rust-cache == 'true' }} + + - run: cargo +"${MSRV}" build --profile no-debug --bin prek + env: + MSRV: ${{ steps.msrv.outputs.value }} + + - run: ./target/no-debug/prek --version + + build-binary-linux-libc: + name: "build binary | linux libc" + timeout-minutes: 10 + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false + + - uses: rui314/setup-mold@9c9c13bf4c3f1adef0cc596abc155580bcb04444 # v1 + + - uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1 + with: + save-if: ${{ inputs.save-rust-cache == 'true' }} + + - name: "Build" + run: cargo build --profile no-debug --bin prek + + - name: "Upload binary" + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + with: + name: prek-linux-libc-${{ github.sha }} + path: | + ./target/no-debug/prek + retention-days: 1 + + build-binary-macos-aarch64: + name: "build binary | macos aarch64" + timeout-minutes: 10 + runs-on: macos-latest + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false + + - uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1 + with: + save-if: ${{ inputs.save-rust-cache == 'true' }} + + - name: "Build" + run: cargo build --profile no-debug --bin prek + + - name: "Upload binary" + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + with: + name: prek-macos-aarch64-${{ github.sha }} + path: | + ./target/no-debug/prek + retention-days: 1 + + build-binary-windows-x86_64: + name: "build binary | windows x86_64" + timeout-minutes: 10 + runs-on: windows-latest + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false + + - name: Setup Dev Drive + run: ${{ github.workspace }}/.github/workflows/setup-dev-drive.ps1 + + # actions/checkout does not let us clone into anywhere outside ${{ github.workspace }}, so we have to copy the clone... + - name: Copy Git Repo to Dev Drive + run: | + Copy-Item -Path "${{ github.workspace }}" -Destination "$Env:PREK_WORKSPACE" -Recurse + + - uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1 + with: + workspaces: ${{ env.PREK_WORKSPACE }} + save-if: ${{ inputs.save-rust-cache == 'true' }} + + - name: "Build" + working-directory: ${{ env.PREK_WORKSPACE }} + run: cargo build --profile no-debug --bin prek + + - name: "Upload binary" + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + with: + name: prek-windows-x86_64-${{ github.sha }} + path: | + ${{ env.PREK_WORKSPACE }}/target/no-debug/prek.exe + retention-days: 1 diff --git a/.github/workflows/build-docker.yml b/.github/workflows/build-docker.yml index fc913ca17..3f23d3ba9 100644 --- a/.github/workflows/build-docker.yml +++ b/.github/workflows/build-docker.yml @@ -12,9 +12,6 @@ on: plan: required: true type: string - pull_request: - paths: - - .github/workflows/build-docker.yml env: PREK_BASE_IMG: ghcr.io/${{ github.repository_owner }}/prek @@ -24,8 +21,29 @@ permissions: packages: write # zizmor: ignore[excessive-permissions] jobs: + plan: + runs-on: ubuntu-slim + outputs: + publish: ${{ steps.plan.outputs.publish }} + steps: + - name: Plan + id: plan + shell: bash + env: + HAS_PLAN: ${{ inputs.plan != '' }} + HAS_IMPLICIT_TAG: ${{ inputs.plan != '' && fromJson(inputs.plan).announcement_tag_is_implicit }} + run: | + [[ "$HAS_PLAN" == "true" && "$HAS_IMPLICIT_TAG" != "true" ]] && publish=1 + + if [[ "$publish" ]]; then + echo "publish=true" >> "$GITHUB_OUTPUT" + else + echo "publish=false" >> "$GITHUB_OUTPUT" + fi + docker-build: name: Build Docker image ghcr.io/j178/prek for ${{ matrix.platform }} + needs: plan runs-on: ubuntu-latest environment: name: release @@ -43,13 +61,14 @@ jobs: - uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0 - uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0 + if: ${{ needs.plan.outputs.publish == 'true' }} with: registry: ghcr.io username: ${{ github.repository_owner }} password: ${{ secrets.GITHUB_TOKEN }} - name: Check tag consistency - if: ${{ inputs.plan != '' && !fromJson(inputs.plan).announcement_tag_is_implicit }} + if: ${{ needs.plan.outputs.publish == 'true' }} env: TAG: ${{ inputs.plan != '' && fromJson(inputs.plan).announcement_tag || 'dry-run' }} run: | @@ -72,8 +91,8 @@ jobs: images: ${{ env.PREK_BASE_IMG }} # Defining this makes sure the org.opencontainers.image.version OCI label becomes the actual release version and not the branch name tags: | - type=raw,value=dry-run,enable=${{ inputs.plan == '' || fromJson(inputs.plan).announcement_tag_is_implicit }} - type=semver,pattern={{ raw }},value=${{ inputs.plan != '' && fromJson(inputs.plan).announcement_tag || 'dry-run' }},enable=${{ inputs.plan != '' && !fromJson(inputs.plan).announcement_tag_is_implicit }} + type=raw,value=dry-run,enable=${{ needs.plan.outputs.publish != 'true' }} + type=semver,pattern={{ raw }},value=${{ inputs.plan != '' && fromJson(inputs.plan).announcement_tag || 'dry-run' }},enable=${{ needs.plan.outputs.publish == 'true' }} - name: Normalize Platform Pair (replace / with -) run: | @@ -90,7 +109,7 @@ jobs: cache-from: type=gha,scope=prek-${{ env.PLATFORM_TUPLE }} cache-to: type=gha,mode=min,scope=prek-${{ env.PLATFORM_TUPLE }} labels: ${{ steps.meta.outputs.labels }} - outputs: type=image,name=${{ env.PREK_BASE_IMG }},push-by-digest=true,name-canonical=true,push=${{ inputs.plan != '' && !fromJson(inputs.plan).announcement_tag_is_implicit }} + outputs: type=image,name=${{ env.PREK_BASE_IMG }},push-by-digest=true,name-canonical=true,push=${{ needs.plan.outputs.publish == 'true' }} - name: Export digests env: @@ -113,13 +132,14 @@ jobs: environment: name: release needs: + - plan - docker-build permissions: contents: read packages: write id-token: write attestations: write - if: ${{ inputs.plan != '' && !fromJson(inputs.plan).announcement_tag_is_implicit }} + if: ${{ needs.plan.outputs.publish == 'true' }} steps: - name: Download digests uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 diff --git a/.github/workflows/build-binaries.yml b/.github/workflows/build-release-binaries.yml similarity index 98% rename from .github/workflows/build-binaries.yml rename to .github/workflows/build-release-binaries.yml index 1e05d0b35..7e31276f8 100644 --- a/.github/workflows/build-binaries.yml +++ b/.github/workflows/build-release-binaries.yml @@ -4,9 +4,9 @@ # Assumed to run as a subworkflow of .github/workflows/release.yml; specifically, as a local # artifacts job within `cargo-dist`. # -# Adapted from https://github.com/astral-sh/uv/blob/main/.github/workflows/build-binaries.yml +# Adapted from https://github.com/astral-sh/uv/blob/main/.github/workflows/build-release-binaries.yml -name: "Build binaries" +name: "Build release binaries" on: workflow_call: @@ -14,15 +14,8 @@ on: plan: required: true type: string - pull_request: - paths: - # When we change pyproject.toml, we want to ensure that the maturin builds still work. - - pyproject.toml - # And when we change this workflow itself... - - .github/workflows/build-binaries.yml -permissions: - contents: read +permissions: {} concurrency: group: ${{ github.workflow }}-${{ github.ref }} @@ -150,7 +143,6 @@ jobs: *.tar.gz *.sha256 - linux: runs-on: ubuntu-latest strategy: diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4e7be7a6b..f55bf5f77 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -38,71 +38,81 @@ env: jobs: plan: - runs-on: ubuntu-latest + runs-on: ubuntu-slim outputs: - test-code: ${{ !contains(github.event.pull_request.labels.*.name, 'test:skip') && (steps.changed.outputs.any_code_changed == 'true' || github.ref == 'refs/heads/master') }} - save-rust-cache: ${{ github.ref == 'refs/heads/master' || steps.changed.outputs.cache_changed == 'true' }} + test-code: ${{ steps.plan.outputs.test_code }} + save-rust-cache: ${{ steps.plan.outputs.save_rust_cache }} language-test-matrix: ${{ steps.nextest.outputs.language-test-matrix }} ci-core-filter: ${{ steps.nextest.outputs.ci-core-filter }} - # Run benchmarks if Rust code or benchmark-related files changed - run-bench: ${{ !contains(github.event.pull_request.labels.*.name, 'test:skip') && (steps.changed.outputs.rust_code_changed == 'true' || steps.changed.outputs.bench_related_changed == 'true' || github.ref == 'refs/heads/master') }} + run-bench: ${{ steps.plan.outputs.run_bench }} + run-zizmor: ${{ steps.plan.outputs.run_zizmor }} + build-release-binaries: ${{ steps.plan.outputs.build_release_binaries }} + build-docker: ${{ steps.plan.outputs.build_docker }} steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: fetch-depth: 0 persist-credentials: false - - name: "Determine changed files" - id: changed + - name: "Plan" + id: plan shell: bash + env: + GH_REF: ${{ github.ref }} + HAS_SKIP_LABEL: ${{ contains(github.event.pull_request.labels.*.name, 'test:skip') }} + HAS_BUILD_SKIP_LABEL: ${{ contains(github.event.pull_request.labels.*.name, 'build:skip') }} + HAS_BUILD_SKIP_DOCKER_LABEL: ${{ contains(github.event.pull_request.labels.*.name, 'build:skip-docker') }} + HAS_BUILD_SKIP_RELEASE_LABEL: ${{ contains(github.event.pull_request.labels.*.name, 'build:skip-release') }} + HAS_BUILD_RELEASE_LABEL: ${{ contains(github.event.pull_request.labels.*.name, 'build:release') }} + BASE_SHA: ${{ github.event.pull_request.base.sha }} run: | - CHANGED_FILES=$(git diff --name-only ${{ github.event.pull_request.base.sha || 'origin/master' }}...HEAD) - - ANY_CODE_CHANGED=false - CACHE_CHANGED=false - RUST_CODE_CHANGED=false - BENCH_RELATED_CHANGED=false + [[ "$GH_REF" == "refs/heads/master" ]] && on_master_branch=1 + [[ "$HAS_SKIP_LABEL" == "true" ]] && has_skip_label=1 + [[ "$HAS_BUILD_SKIP_LABEL" == "true" ]] && has_build_skip_label=1 + [[ "$HAS_BUILD_SKIP_DOCKER_LABEL" == "true" ]] && has_build_skip_docker_label=1 + [[ "$HAS_BUILD_SKIP_RELEASE_LABEL" == "true" ]] && has_build_skip_release_label=1 + [[ "$HAS_BUILD_RELEASE_LABEL" == "true" ]] && has_build_release_label=1 while IFS= read -r file; do - # Check if cache-relevant files changed (Cargo files, toolchain, workflows) - if [[ "${file}" == "Cargo.lock" || "${file}" == "Cargo.toml" || "${file}" == "rust-toolchain.toml" || "${file}" == ".cargo/config.toml" || "${file}" =~ ^crates/.*/Cargo\.toml$ || "${file}" =~ ^\.github/workflows/.*\.yml$ ]]; then - echo "Detected cache-relevant change: ${file}" - CACHE_CHANGED=true - fi - - # Check if Rust code changed (for benchmarks) - if [[ "${file}" =~ \.rs$ ]] || [[ "${file}" =~ Cargo\.toml$ ]] || [[ "${file}" == "Cargo.lock" ]] || [[ "${file}" == "rust-toolchain.toml" ]] || [[ "${file}" =~ ^\.cargo/ ]]; then - echo "Detected Rust code change: ${file}" - RUST_CODE_CHANGED=true - fi - - if [[ "${file}" == ".github/workflows/performance.yml" ]] || [[ "${file}" =~ ^scripts/hyperfine-.*\.sh$ ]]; then - echo "Detected benchmark-related change: ${file}" - BENCH_RELATED_CHANGED=true - fi - - if [[ "${file}" =~ ^docs/ ]]; then - echo "Skipping ${file} (matches docs/ pattern)" - continue - fi - if [[ "${file}" =~ ^mkdocs.*\.yml$ ]]; then - echo "Skipping ${file} (matches mkdocs*.yml pattern)" - continue - fi - if [[ "${file}" =~ \.md$ ]]; then - echo "Skipping ${file} (matches *.md pattern)" - continue - fi - - echo "Detected code change in: ${file}" - ANY_CODE_CHANGED=true - - done <<< "${CHANGED_FILES}" + [[ -z "$file" ]] && continue + [[ "$file" =~ \.rs$ ]] && rust_code_changed=1 + [[ "$file" == "Cargo.toml" || "$file" == "Cargo.lock" || "$file" =~ ^crates/.*/Cargo\.toml$ ]] && rust_deps_changed=1 + [[ "$file" == "rust-toolchain.toml" || "$file" =~ ^\.cargo/ ]] && rust_config_changed=1 + [[ "$file" == "pyproject.toml" || "$file" =~ ^python/ ]] && python_config_changed=1 + [[ "$file" =~ ^\.github/workflows/.*\.ya?ml$ ]] && workflow_changed=1 + [[ "$file" == ".github/workflows/ci.yml" ]] && ci_workflow_changed=1 + [[ "$file" == ".github/workflows/build-release-binaries.yml" || "$file" == ".github/workflows/release.yml" ]] && release_workflow_changed=1 + [[ "$file" == "dist-workspace.toml" ]] && release_config_changed=1 + [[ "$file" == ".github/zizmor.yml" ]] && zizmor_config_changed=1 + [[ "$file" == "Dockerfile" ]] && dockerfile_changed=1 + [[ "$file" == ".github/workflows/build-docker.yml" ]] && docker_workflow_changed=1 + [[ "$file" == ".github/workflows/performance.yml" ]] && bench_workflow_changed=1 + [[ "$file" =~ ^scripts/hyperfine-.*\.sh$ ]] && bench_scripts_changed=1 + [[ "$file" =~ ^docs/ || "$file" =~ ^mkdocs.*\.yml$ || "$file" =~ \.md$ ]] && continue + any_code_changed=1 + done <<< "$(git diff --name-only "${BASE_SHA:-origin/master}...HEAD")" + + [[ $rust_code_changed || $rust_deps_changed || $rust_config_changed ]] && any_rust_changed=1 + [[ $rust_deps_changed || $rust_config_changed || $workflow_changed ]] && cache_relevant_changed=1 + [[ $bench_workflow_changed || $bench_scripts_changed ]] && bench_related_changed=1 + [[ $python_config_changed || $rust_deps_changed || $rust_config_changed || $release_workflow_changed || $release_config_changed || $ci_workflow_changed ]] && release_build_changed=1 + [[ $python_config_changed || $rust_deps_changed || $rust_config_changed || $release_config_changed || $dockerfile_changed || $docker_workflow_changed || $ci_workflow_changed ]] && docker_build_changed=1 + + [[ ! $has_skip_label && ($any_code_changed || $on_master_branch) ]] && test_code=1 + [[ $on_master_branch || $cache_relevant_changed ]] && save_rust_cache=1 + [[ ! $has_skip_label && ($any_rust_changed || $bench_related_changed || $on_master_branch) ]] && run_bench=1 + [[ ! $has_skip_label && ($workflow_changed || $zizmor_config_changed || $on_master_branch) ]] && run_zizmor=1 + [[ ! $has_skip_label && ! $has_build_skip_label && ! $has_build_skip_release_label && ($release_build_changed || $has_build_release_label) ]] && build_release_binaries=1 + [[ ! $has_skip_label && ! $has_build_skip_label && ! $has_build_skip_docker_label && $docker_build_changed ]] && build_docker=1 + + out() { [[ "$2" ]] && echo "$1=true" || echo "$1=false"; } { - echo "any_code_changed=${ANY_CODE_CHANGED}" - echo "cache_changed=${CACHE_CHANGED}" - echo "rust_code_changed=${RUST_CODE_CHANGED}" - echo "bench_related_changed=${BENCH_RELATED_CHANGED}" + out test_code "$test_code" + out save_rust_cache "$save_rust_cache" + out run_bench "$run_bench" + out run_zizmor "$run_zizmor" + out build_release_binaries "$build_release_binaries" + out build_docker "$build_docker" } >> "${GITHUB_OUTPUT}" - name: "Generate nextest filters" @@ -112,7 +122,6 @@ jobs: python3 scripts/generate_ci_matrix.py --group-size 4 --github-output >> "${GITHUB_OUTPUT}" lint: - name: "lint" timeout-minutes: 10 runs-on: ubuntu-latest steps: @@ -129,7 +138,6 @@ jobs: PREK_SKIP: cargo-fmt,cargo-clippy check-release: - name: "check release" needs: plan timeout-minutes: 10 runs-on: ubuntu-latest @@ -150,6 +158,35 @@ jobs: echo "dist plan completed successfully" cat plan-dist-manifest.json + check-zizmor: + needs: plan + if: ${{ needs.plan.outputs.run-zizmor == 'true' }} + uses: ./.github/workflows/zizmor.yml + permissions: + contents: read + security-events: write + + build-release-binaries: + needs: plan + if: ${{ needs.plan.outputs.build-release-binaries == 'true' }} + uses: ./.github/workflows/build-release-binaries.yml + with: + # CI has no cargo-dist manifest; release.yml passes the real plan when publishing. + plan: "" + + build-docker: + needs: plan + if: ${{ needs.plan.outputs.build-docker == 'true' }} + uses: ./.github/workflows/build-docker.yml + with: + # CI has no cargo-dist manifest; an empty plan keeps Docker builds in dry-run mode. + plan: "" + permissions: + contents: read + id-token: write + packages: write + attestations: write + cargo-clippy-linux: name: "cargo clippy | ubuntu" needs: plan @@ -612,121 +649,37 @@ jobs: working-directory: cpython run: cargo run -p prek -- --all-files - build-binary-msrv: - needs: plan - if: ${{ needs.plan.outputs.test-code == 'true' }} - name: "build binary | msrv" - runs-on: ubuntu-latest - timeout-minutes: 10 - steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - with: - persist-credentials: false - - name: "Read MSRV from Cargo.toml" - id: msrv - run: | - MSRV=$(grep -m1 'rust-version' Cargo.toml | sed 's/.*"\([^"]*\)".*/\1/') - echo "value=$MSRV" >> "$GITHUB_OUTPUT" - - name: "Install Rust toolchain" - run: rustup default "${MSRV}" - env: - MSRV: ${{ steps.msrv.outputs.value }} - - name: "Install mold" - uses: rui314/setup-mold@9c9c13bf4c3f1adef0cc596abc155580bcb04444 # v1 - - uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1 - with: - save-if: ${{ needs.plan.outputs.save-rust-cache == 'true' }} - - run: cargo +"${MSRV}" build --profile no-debug --bin prek - env: - MSRV: ${{ steps.msrv.outputs.value }} - - run: ./target/no-debug/prek --version - - build-binary-linux-libc: - needs: plan - if: ${{ needs.plan.outputs.test-code == 'true' }} - timeout-minutes: 10 - runs-on: ubuntu-latest - name: "build binary | linux libc" - steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - with: - persist-credentials: false - - - uses: rui314/setup-mold@9c9c13bf4c3f1adef0cc596abc155580bcb04444 # v1 - - - uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1 - with: - save-if: ${{ needs.plan.outputs.save-rust-cache == 'true' }} - - - name: "Build" - run: cargo build --profile no-debug --bin prek - - - name: "Upload binary" - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 - with: - name: prek-linux-libc-${{ github.sha }} - path: | - ./target/no-debug/prek - retention-days: 1 - - build-binary-macos-aarch64: + build-dev-binaries: needs: plan if: ${{ needs.plan.outputs.test-code == 'true' }} - timeout-minutes: 10 - runs-on: macos-latest - name: "build binary | macos aarch64" - steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - with: - persist-credentials: false - - - uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1 - with: - save-if: ${{ needs.plan.outputs.save-rust-cache == 'true' }} - - - name: "Build" - run: cargo build --profile no-debug --bin prek - - - name: "Upload binary" - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 - with: - name: prek-macos-aarch64-${{ github.sha }} - path: | - ./target/no-debug/prek - retention-days: 1 + uses: ./.github/workflows/build-dev-binaries.yml + with: + save-rust-cache: ${{ needs.plan.outputs.save-rust-cache }} - build-binary-windows-x86_64: - needs: plan - if: ${{ needs.plan.outputs.test-code == 'true' }} - timeout-minutes: 10 - runs-on: windows-latest - name: "build binary | windows x86_64" + required-checks-passed: + name: "all required jobs passed" + if: always() + needs: + - lint + - check-release + - check-zizmor + - cargo-clippy-linux + - cargo-clippy-windows + - cargo-shear + - cargo-test-without-uv + - cargo-test + - cargo-test-windows + - language-tests + - ecosystem-cpython + - build-dev-binaries + runs-on: ubuntu-slim steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - with: - persist-credentials: false - - - name: Setup Dev Drive - run: ${{ github.workspace }}/.github/workflows/setup-dev-drive.ps1 - - # actions/checkout does not let us clone into anywhere outside ${{ github.workspace }}, so we have to copy the clone... - - name: Copy Git Repo to Dev Drive + - name: "Check required jobs passed" run: | - Copy-Item -Path "${{ github.workspace }}" -Destination "$Env:PREK_WORKSPACE" -Recurse - - - uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1 - with: - workspaces: ${{ env.PREK_WORKSPACE }} - save-if: ${{ needs.plan.outputs.save-rust-cache == 'true' }} - - - name: "Build" - working-directory: ${{ env.PREK_WORKSPACE }} - run: cargo build --profile no-debug --bin prek - - - name: "Upload binary" - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 - with: - name: prek-windows-x86_64-${{ github.sha }} - path: | - ${{ env.PREK_WORKSPACE }}/target/no-debug/prek.exe - retention-days: 1 + failing=$(echo "$NEEDS_JSON" | jq -r 'to_entries[] | select(.value.result != "success" and .value.result != "skipped") | "\(.key): \(.value.result)"') + if [ -n "$failing" ]; then + echo "$failing" + exit 1 + fi + env: + NEEDS_JSON: ${{ toJSON(needs) }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 076f471b5..86b311eb5 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -90,11 +90,11 @@ jobs: name: artifacts-plan-dist-manifest path: plan-dist-manifest.json - custom-build-binaries: + custom-build-release-binaries: needs: - plan if: ${{ needs.plan.outputs.publishing == 'true' || fromJson(needs.plan.outputs.val).ci.github.pr_run_mode == 'upload' || inputs.tag == 'dry-run' }} - uses: ./.github/workflows/build-binaries.yml + uses: ./.github/workflows/build-release-binaries.yml with: plan: ${{ needs.plan.outputs.val }} secrets: inherit @@ -117,7 +117,7 @@ jobs: build-global-artifacts: needs: - plan - - custom-build-binaries + - custom-build-release-binaries - custom-build-docker runs-on: "ubuntu-latest" env: @@ -164,11 +164,11 @@ jobs: host: needs: - plan - - custom-build-binaries + - custom-build-release-binaries - custom-build-docker - build-global-artifacts # Only run if we're "publishing", and only if plan, local and global didn't fail (skipped is fine) - if: ${{ always() && needs.plan.result == 'success' && needs.plan.outputs.publishing == 'true' && (needs.build-global-artifacts.result == 'skipped' || needs.build-global-artifacts.result == 'success') && (needs.custom-build-binaries.result == 'skipped' || needs.custom-build-binaries.result == 'success') && (needs.custom-build-docker.result == 'skipped' || needs.custom-build-docker.result == 'success') }} + if: ${{ always() && needs.plan.result == 'success' && needs.plan.outputs.publishing == 'true' && (needs.build-global-artifacts.result == 'skipped' || needs.build-global-artifacts.result == 'success') && (needs.custom-build-release-binaries.result == 'skipped' || needs.custom-build-release-binaries.result == 'success') && (needs.custom-build-docker.result == 'skipped' || needs.custom-build-docker.result == 'success') }} env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} runs-on: "ubuntu-latest" diff --git a/.github/workflows/zizmor.yml b/.github/workflows/zizmor.yml index 187e06d3a..7b68fda27 100644 --- a/.github/workflows/zizmor.yml +++ b/.github/workflows/zizmor.yml @@ -1,10 +1,7 @@ name: Run zizmor on: - push: - branches: ["master"] - pull_request: - branches: ["**"] + workflow_call: permissions: {} @@ -13,6 +10,7 @@ jobs: name: Run zizmor runs-on: ubuntu-latest permissions: + contents: read security-events: write steps: - name: Checkout repository diff --git a/dist-workspace.toml b/dist-workspace.toml index 54a967148..f481e519a 100644 --- a/dist-workspace.toml +++ b/dist-workspace.toml @@ -45,7 +45,7 @@ targets = [ "i686-pc-windows-msvc", ] # Local artifacts jobs to run in CI -local-artifacts-jobs = ["./build-binaries", "./build-docker"] +local-artifacts-jobs = ["./build-release-binaries", "./build-docker"] # Publish jobs to run in CI publish-jobs = ["./publish-crates", "./publish-pypi", "./publish-npm"] # Post-announce jobs to run in CI From 5b5b81535a3c3de1f5d062f155b7a7a0443771e3 Mon Sep 17 00:00:00 2001 From: Jo <10510431+j178@users.noreply.github.com> Date: Sun, 3 May 2026 22:35:36 +0800 Subject: [PATCH 12/23] Avoid template expansion in language test filters (#2031) --- .github/workflows/ci.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f55bf5f77..6420e80e8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -578,6 +578,7 @@ jobs: # Ruby auto_download test queries the GitHub Releases API; without a # token, shared runners quickly hit the 60 req/hour rate limit. GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + NEXTEST_FILTER: ${{ matrix.filter }} run: | cargo llvm-cov nextest \ --lcov \ @@ -586,13 +587,14 @@ jobs: --cargo-profile fast-build \ --features schemars \ --profile ci-language \ - -E '${{ matrix.filter }}' + -E "$NEXTEST_FILTER" - name: "Run language tests (windows)" if: ${{ matrix.os == 'windows-latest' }} shell: pwsh env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + NEXTEST_FILTER: ${{ matrix.filter }} run: | # Remove msys64 from PATH for Rust compilation $env:PATH = ($env:PATH -split ';' | Where-Object { $_ -notmatch '\\msys64\\' }) -join ';' @@ -604,7 +606,7 @@ jobs: --cargo-profile fast-build ` --features schemars ` --profile ci-language ` - -E '${{ matrix.filter }}' + -E $env:NEXTEST_FILTER if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } From a451213507b2a17409aad9d1329583b1b2a79ea5 Mon Sep 17 00:00:00 2001 From: Jo <10510431+j178@users.noreply.github.com> Date: Mon, 4 May 2026 16:37:42 +0800 Subject: [PATCH 13/23] Update CI planning checks (#2038) --- .github/workflows/ci.yml | 46 +++++++++++++++++++++++++++++++----- .github/workflows/zizmor.yml | 22 ----------------- 2 files changed, 40 insertions(+), 28 deletions(-) delete mode 100644 .github/workflows/zizmor.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6420e80e8..02bb9b0ef 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -46,6 +46,7 @@ jobs: ci-core-filter: ${{ steps.nextest.outputs.ci-core-filter }} run-bench: ${{ steps.plan.outputs.run_bench }} run-zizmor: ${{ steps.plan.outputs.run_zizmor }} + check-docs: ${{ steps.plan.outputs.check_docs }} build-release-binaries: ${{ steps.plan.outputs.build_release_binaries }} build-docker: ${{ steps.plan.outputs.build_docker }} steps: @@ -78,10 +79,12 @@ jobs: [[ "$file" =~ \.rs$ ]] && rust_code_changed=1 [[ "$file" == "Cargo.toml" || "$file" == "Cargo.lock" || "$file" =~ ^crates/.*/Cargo\.toml$ ]] && rust_deps_changed=1 [[ "$file" == "rust-toolchain.toml" || "$file" =~ ^\.cargo/ ]] && rust_config_changed=1 - [[ "$file" == "pyproject.toml" || "$file" =~ ^python/ ]] && python_config_changed=1 + [[ "$file" == "pyproject.toml" ]] && pyproject_changed=1 + [[ "$file" == "docs/reference/cli.md" || "$file" == "docs/reference/configuration.md" || "$file" == "prek.schema.json" ]] && generated_from_code_changed=1 + [[ "$file" =~ ^docs/ || "$file" == "mkdocs.yml" || "$file" == "pyproject.toml" || "$file" == "uv.lock" ]] && docs_related_changed=1 [[ "$file" =~ ^\.github/workflows/.*\.ya?ml$ ]] && workflow_changed=1 [[ "$file" == ".github/workflows/ci.yml" ]] && ci_workflow_changed=1 - [[ "$file" == ".github/workflows/build-release-binaries.yml" || "$file" == ".github/workflows/release.yml" ]] && release_workflow_changed=1 + [[ "$file" == ".github/workflows/build-release-binaries.yml" ]] && release_binaries_workflow_changed=1 [[ "$file" == "dist-workspace.toml" ]] && release_config_changed=1 [[ "$file" == ".github/zizmor.yml" ]] && zizmor_config_changed=1 [[ "$file" == "Dockerfile" ]] && dockerfile_changed=1 @@ -95,13 +98,14 @@ jobs: [[ $rust_code_changed || $rust_deps_changed || $rust_config_changed ]] && any_rust_changed=1 [[ $rust_deps_changed || $rust_config_changed || $workflow_changed ]] && cache_relevant_changed=1 [[ $bench_workflow_changed || $bench_scripts_changed ]] && bench_related_changed=1 - [[ $python_config_changed || $rust_deps_changed || $rust_config_changed || $release_workflow_changed || $release_config_changed || $ci_workflow_changed ]] && release_build_changed=1 - [[ $python_config_changed || $rust_deps_changed || $rust_config_changed || $release_config_changed || $dockerfile_changed || $docker_workflow_changed || $ci_workflow_changed ]] && docker_build_changed=1 + [[ $pyproject_changed || $release_binaries_workflow_changed ]] && release_build_changed=1 + [[ $rust_deps_changed || $rust_config_changed || $dockerfile_changed || $docker_workflow_changed ]] && docker_build_changed=1 - [[ ! $has_skip_label && ($any_code_changed || $on_master_branch) ]] && test_code=1 + [[ ! $has_skip_label && ($any_code_changed || $generated_from_code_changed || $on_master_branch) ]] && test_code=1 [[ $on_master_branch || $cache_relevant_changed ]] && save_rust_cache=1 [[ ! $has_skip_label && ($any_rust_changed || $bench_related_changed || $on_master_branch) ]] && run_bench=1 [[ ! $has_skip_label && ($workflow_changed || $zizmor_config_changed || $on_master_branch) ]] && run_zizmor=1 + [[ ! $has_skip_label && ($docs_related_changed || $on_master_branch) ]] && check_docs=1 [[ ! $has_skip_label && ! $has_build_skip_label && ! $has_build_skip_release_label && ($release_build_changed || $has_build_release_label) ]] && build_release_binaries=1 [[ ! $has_skip_label && ! $has_build_skip_label && ! $has_build_skip_docker_label && $docker_build_changed ]] && build_docker=1 @@ -111,6 +115,7 @@ jobs: out save_rust_cache "$save_rust_cache" out run_bench "$run_bench" out run_zizmor "$run_zizmor" + out check_docs "$check_docs" out build_release_binaries "$build_release_binaries" out build_docker "$build_docker" } >> "${GITHUB_OUTPUT}" @@ -159,12 +164,40 @@ jobs: cat plan-dist-manifest.json check-zizmor: + name: Run zizmor needs: plan if: ${{ needs.plan.outputs.run-zizmor == 'true' }} - uses: ./.github/workflows/zizmor.yml + runs-on: ubuntu-latest permissions: contents: read security-events: write + steps: + - name: Checkout repository + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false + + - name: Run zizmor + uses: zizmorcore/zizmor-action@b1d7e1fb5de872772f31590499237e7cce841e8e # v0.5.3 + + check-docs: + needs: plan + if: ${{ needs.plan.outputs.check-docs == 'true' }} + timeout-minutes: 10 + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false + + - uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0 + with: + version: ${{ env.UV_VERSION }} + + - name: Build documentation + run: | + uv run --group docs zensical build + uv run --group docs llmstxt-standalone build build-release-binaries: needs: plan @@ -665,6 +698,7 @@ jobs: - lint - check-release - check-zizmor + - check-docs - cargo-clippy-linux - cargo-clippy-windows - cargo-shear diff --git a/.github/workflows/zizmor.yml b/.github/workflows/zizmor.yml deleted file mode 100644 index 7b68fda27..000000000 --- a/.github/workflows/zizmor.yml +++ /dev/null @@ -1,22 +0,0 @@ -name: Run zizmor - -on: - workflow_call: - -permissions: {} - -jobs: - zizmor: - name: Run zizmor - runs-on: ubuntu-latest - permissions: - contents: read - security-events: write - steps: - - name: Checkout repository - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - with: - persist-credentials: false - - - name: Run zizmor - uses: zizmorcore/zizmor-action@b1d7e1fb5de872772f31590499237e7cce841e8e # v0.5.3 From 278a9bcc029509328bfaec3b6c03f3f6e8b015aa Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 4 May 2026 16:55:46 +0800 Subject: [PATCH 14/23] Update Rust crate async-compression to v0.4.42 (#2034) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR contains the following updates: | Package | Type | Update | Change | |---|---|---|---| | [async-compression](https://redirect.github.com/Nullus157/async-compression) | workspace.dependencies | patch | `0.4.41` → `0.4.42` | --- ### Release Notes
Nullus157/async-compression (async-compression) ### [`v0.4.42`](https://redirect.github.com/Nullus157/async-compression/releases/tag/async-compression-v0.4.42) [Compare Source](https://redirect.github.com/Nullus157/async-compression/compare/async-compression-v0.4.41...async-compression-v0.4.42) ##### Other - Include license files in published crates ([#​467](https://redirect.github.com/Nullus157/async-compression/pull/467)) - Fix async-compression CHANGELOG ordering ([#​463](https://redirect.github.com/Nullus157/async-compression/pull/463))
--- ### Configuration 📅 **Schedule**: (UTC) - Branch creation - Between 12:00 AM and 03:59 AM, only on Monday (`* 0-3 * * 1`) - Automerge - At any time (no schedule defined) 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. 🔕 **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR was generated by [Mend Renovate](https://mend.io/renovate/). View the [repository job log](https://developer.mend.io/github/j178/prek). Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- Cargo.lock | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 198913e69..81987fa33 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -95,7 +95,7 @@ version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" dependencies = [ - "windows-sys 0.61.2", + "windows-sys 0.60.2", ] [[package]] @@ -106,7 +106,7 @@ checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" dependencies = [ "anstyle", "once_cell_polyfill", - "windows-sys 0.61.2", + "windows-sys 0.60.2", ] [[package]] @@ -199,9 +199,9 @@ dependencies = [ [[package]] name = "async-compression" -version = "0.4.41" +version = "0.4.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0f9ee0f6e02ffd7ad5816e9464499fba7b3effd01123b515c41d1697c43dad1" +checksum = "e79b3f8a79cccc2898f31920fc69f304859b3bd567490f75ebf51ae1c792a9ac" dependencies = [ "compression-codecs", "compression-core", @@ -550,9 +550,9 @@ dependencies = [ [[package]] name = "compression-codecs" -version = "0.4.37" +version = "0.4.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb7b51a7d9c967fc26773061ba86150f19c50c0d65c887cb1fbe295fd16619b7" +checksum = "ce2548391e9c1929c21bf6aa2680af86fe4c1b33e6cea9ac1cfeec0bd11218cf" dependencies = [ "compression-core", "flate2", @@ -562,9 +562,9 @@ dependencies = [ [[package]] name = "compression-core" -version = "0.4.31" +version = "0.4.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75984efb6ed102a0d42db99afb6c1948f0380d1d91808d5529916e6c08b49d8d" +checksum = "cc14f565cf027a105f7a44ccf9e5b424348421a1d8952a8fc9d499d313107789" [[package]] name = "console" @@ -792,7 +792,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.61.2", + "windows-sys 0.52.0", ] [[package]] @@ -1488,7 +1488,7 @@ checksum = "3640c1c38b8e4e43584d8df18be5fc6b0aa314ce6ebf51b53313d4306cca8e46" dependencies = [ "hermit-abi", "libc", - "windows-sys 0.61.2", + "windows-sys 0.52.0", ] [[package]] @@ -1863,7 +1863,7 @@ version = "0.50.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" dependencies = [ - "windows-sys 0.61.2", + "windows-sys 0.59.0", ] [[package]] @@ -2551,7 +2551,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys", - "windows-sys 0.61.2", + "windows-sys 0.52.0", ] [[package]] @@ -2608,7 +2608,7 @@ dependencies = [ "security-framework", "security-framework-sys", "webpki-root-certs", - "windows-sys 0.61.2", + "windows-sys 0.52.0", ] [[package]] @@ -2917,7 +2917,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e" dependencies = [ "libc", - "windows-sys 0.61.2", + "windows-sys 0.60.2", ] [[package]] @@ -3078,7 +3078,7 @@ dependencies = [ "getrandom 0.4.2", "once_cell", "rustix", - "windows-sys 0.61.2", + "windows-sys 0.52.0", ] [[package]] @@ -3088,7 +3088,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "230a1b821ccbd75b185820a1f1ff7b14d21da1e442e22c0863ea5f08771a8874" dependencies = [ "rustix", - "windows-sys 0.61.2", + "windows-sys 0.59.0", ] [[package]] @@ -3729,7 +3729,7 @@ version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "windows-sys 0.61.2", + "windows-sys 0.52.0", ] [[package]] From 32a5032d1163f2929c8a4ee8e2ba35ef9c3b4454 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 4 May 2026 16:56:08 +0800 Subject: [PATCH 15/23] Update Rust crate libc to v0.2.186 (#2035) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR contains the following updates: | Package | Type | Update | Change | |---|---|---|---| | [libc](https://redirect.github.com/rust-lang/libc) | workspace.dependencies | patch | `0.2.185` → `0.2.186` | --- ### Release Notes
rust-lang/libc (libc) ### [`v0.2.186`](https://redirect.github.com/rust-lang/libc/releases/tag/0.2.186) [Compare Source](https://redirect.github.com/rust-lang/libc/compare/0.2.185...0.2.186) ##### Added - Apple: Add `KEVENT_FLAG_*` constants ([#​5070](https://redirect.github.com/rust-lang/libc/pull/5070)) - Linux: Add `PR_SET_MEMORY_MERGE` and `PR_GET_MEMORY_MERGE` ([#​5060](https://redirect.github.com/rust-lang/libc/pull/5060)) ##### Changed - CI: Migrate FreeBSD CI from Cirrus CI to GitHub Actions ([#​5058](https://redirect.github.com/rust-lang/libc/pull/5058))
--- ### Configuration 📅 **Schedule**: (UTC) - Branch creation - Between 12:00 AM and 03:59 AM, only on Monday (`* 0-3 * * 1`) - Automerge - At any time (no schedule defined) 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. 🔕 **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR was generated by [Mend Renovate](https://mend.io/renovate/). View the [repository job log](https://developer.mend.io/github/j178/prek). Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 81987fa33..221375f08 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1640,9 +1640,9 @@ checksum = "db13adb97ab515a3691f56e4dbab09283d0b86cb45abd991d8634a9d6f501760" [[package]] name = "libc" -version = "0.2.185" +version = "0.2.186" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52ff2c0fe9bc6cb6b14a0592c2ff4fa9ceb83eea9db979b0487cd054946a2b8f" +checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" [[package]] name = "liblzma" From c9bf330ccdc3b483f397245ee348ad3908809de7 Mon Sep 17 00:00:00 2001 From: Jo <10510431+j178@users.noreply.github.com> Date: Mon, 4 May 2026 16:57:35 +0800 Subject: [PATCH 16/23] Point schema docs to SchemaStore (#2039) Closes #2033 --- docs/configuration.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/docs/configuration.md b/docs/configuration.md index b8148ed05..d22a08dd1 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -269,9 +269,7 @@ But if `foo/bar` is itself a project (has its own config), files under `foo/bar` Use [`prek validate-config`](reference/cli.md#prek-validate-config) to validate one or more config files. -If you want IDE completion / validation, prek provides a JSON Schema at [https://prek.j178.dev/docs/prek.schema.json](https://prek.j178.dev/docs/prek.schema.json). - -And the schema is also submitted to the [JSON Schema Store](https://www.schemastore.org/prek.json), so some editors may pick it up automatically. +If you want IDE completion / validation, prek publishes a JSON Schema through the [JSON Schema Store](https://www.schemastore.org/prek.json), so some editors may pick it up automatically. That schema tracks what `prek` accepts today, but `prek` also intentionally tolerates unknown keys for forward compatibility. From 8e60b89284764936e8d06210a8921d2761fa6630 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 4 May 2026 16:58:23 +0800 Subject: [PATCH 17/23] Update GitHub Actions (#2037) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR contains the following updates: | Package | Type | Update | Change | Pending | |---|---|---|---|---| | [dart-lang/setup-dart](https://redirect.github.com/dart-lang/setup-dart) | action | minor | `v1.6.5` → `v1.7.2` | | | [julia-actions/setup-julia](https://redirect.github.com/julia-actions/setup-julia) | action | patch | `v3.0.0` → `v3.0.1` | | | [ruby/setup-ruby](https://redirect.github.com/ruby/setup-ruby) | action | minor | `v1.302.0` → `v1.306.0` | | | [taiki-e/install-action](https://redirect.github.com/taiki-e/install-action) | action | patch | `v2.75.18` → `v2.75.22` | `v2.75.30` (+7) | --- ### Release Notes
dart-lang/setup-dart (dart-lang/setup-dart) ### [`v1.7.2`](https://redirect.github.com/dart-lang/setup-dart/blob/HEAD/CHANGELOG.md#v172) [Compare Source](https://redirect.github.com/dart-lang/setup-dart/compare/v1.7.1...v1.7.2) - Update Node.js requirement to Node 24. - Fix open Dependabot alerts by bumping `undici` to `>=6.24.0`. - Update GitHub Action dependencies (`@actions/core`, `@actions/exec`, `@actions/tool-cache`, `@actions/http-client`). - Update workflow actions to their latest versions (`actions/checkout` v6, `setup-flutter`). ### [`v1.7.1`](https://redirect.github.com/dart-lang/setup-dart/blob/HEAD/CHANGELOG.md#v171) [Compare Source](https://redirect.github.com/dart-lang/setup-dart/compare/v1.7.0...v1.7.1) - Roll `undici` dependency to address [CVE-2025-22150][]. - Update to the latest npm dependencies. - Recompile the action using the new Dart / JavaScript interop. [CVE-2025-22150]: https://redirect.github.com/nodejs/undici/security/advisories/GHSA-c76h-2ccp-4975 ### [`v1.7.0`](https://redirect.github.com/dart-lang/setup-dart/blob/HEAD/CHANGELOG.md#v170) [Compare Source](https://redirect.github.com/dart-lang/setup-dart/compare/v1.6.5...v1.7.0) - Install flutter sdk in publishing step, allowing Flutter packages to be published ([#​68][]) [#​68]: https://redirect.github.com/dart-lang/setup-dart/issues/68
julia-actions/setup-julia (julia-actions/setup-julia) ### [`v3.0.1`](https://redirect.github.com/julia-actions/setup-julia/releases/tag/v3.0.1) [Compare Source](https://redirect.github.com/julia-actions/setup-julia/compare/v3.0.0...v3.0.1) #### What's Changed This is a bugfix release that fixes an error seen when using `min-minor` or `min-patch`. #### Full Changelog **Full Changelog**:
ruby/setup-ruby (ruby/setup-ruby) ### [`v1.306.0`](https://redirect.github.com/ruby/setup-ruby/releases/tag/v1.306.0) [Compare Source](https://redirect.github.com/ruby/setup-ruby/compare/v1.305.0...v1.306.0) ##### What's Changed - Add truffleruby-34.0.1,truffleruby+graalvm-34.0.1 by [@​ruby-builder-bot](https://redirect.github.com/ruby-builder-bot) in [#​909](https://redirect.github.com/ruby/setup-ruby/pull/909) **Full Changelog**: ### [`v1.305.0`](https://redirect.github.com/ruby/setup-ruby/releases/tag/v1.305.0) [Compare Source](https://redirect.github.com/ruby/setup-ruby/compare/v1.304.0...v1.305.0) #### What's Changed - Update CRuby releases on Windows by [@​ruby-builder-bot](https://redirect.github.com/ruby-builder-bot) in [#​908](https://redirect.github.com/ruby/setup-ruby/pull/908) **Full Changelog**: ### [`v1.304.0`](https://redirect.github.com/ruby/setup-ruby/releases/tag/v1.304.0) [Compare Source](https://redirect.github.com/ruby/setup-ruby/compare/v1.303.0...v1.304.0) #### What's Changed - Add jruby-10.1.0.0 by [@​ruby-builder-bot](https://redirect.github.com/ruby-builder-bot) in [#​906](https://redirect.github.com/ruby/setup-ruby/pull/906) **Full Changelog**: ### [`v1.303.0`](https://redirect.github.com/ruby/setup-ruby/releases/tag/v1.303.0) [Compare Source](https://redirect.github.com/ruby/setup-ruby/compare/v1.302.0...v1.303.0) #### What's Changed - Add ruby-4.0.3 by [@​ruby-builder-bot](https://redirect.github.com/ruby-builder-bot) in [#​903](https://redirect.github.com/ruby/setup-ruby/pull/903) **Full Changelog**:
taiki-e/install-action (taiki-e/install-action) ### [`v2.75.22`](https://redirect.github.com/taiki-e/install-action/releases/tag/v2.75.22): 2.75.22 [Compare Source](https://redirect.github.com/taiki-e/install-action/compare/v2.75.21...v2.75.22) - Update `tombi@latest` to 0.9.22. - Update `biome@latest` to 2.4.13. ### [`v2.75.21`](https://redirect.github.com/taiki-e/install-action/releases/tag/v2.75.21): 2.75.21 [Compare Source](https://redirect.github.com/taiki-e/install-action/compare/v2.75.20...v2.75.21) - Update `mise@latest` to 2026.4.19. - Update `tombi@latest` to 0.9.21. - Update `syft@latest` to 1.43.0. ### [`v2.75.20`](https://redirect.github.com/taiki-e/install-action/releases/tag/v2.75.20): 2.75.20 [Compare Source](https://redirect.github.com/taiki-e/install-action/compare/v2.75.19...v2.75.20) - Update `prek@latest` to 0.3.10. - Update `cargo-xwin@latest` to 0.22.0. ### [`v2.75.19`](https://redirect.github.com/taiki-e/install-action/releases/tag/v2.75.19): 2.75.19 [Compare Source](https://redirect.github.com/taiki-e/install-action/compare/v2.75.18...v2.75.19) - Update `wasmtime@latest` to 44.0.0. - Update `tombi@latest` to 0.9.20. - Update `martin@latest` to 1.6.0. - Update `just@latest` to 1.50.0. - Update `mise@latest` to 2026.4.18. - Update `rclone@latest` to 1.73.5.
--- ### Configuration 📅 **Schedule**: (UTC) - Branch creation - Between 12:00 AM and 03:59 AM, only on Monday (`* 0-3 * * 1`) - Automerge - At any time (no schedule defined) 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. 👻 **Immortal**: This PR will be recreated if closed unmerged. Get [config help](https://redirect.github.com/renovatebot/renovate/discussions) if that's undesired. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR was generated by [Mend Renovate](https://mend.io/renovate/). View the [repository job log](https://developer.mend.io/github/j178/prek). Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/ci.yml | 24 ++++++++++++------------ .github/workflows/performance.yml | 4 ++-- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 02bb9b0ef..fda201602 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -282,7 +282,7 @@ jobs: with: persist-credentials: false - name: "Install cargo shear" - uses: taiki-e/install-action@055f5df8c3f65ea01cd41e9dc855becd88953486 # v2.75.18 + uses: taiki-e/install-action@cf525cb33f51aca27cd6fa02034117ab963ff9f1 # v2.75.22 with: tool: cargo-shear - run: cargo shear @@ -306,12 +306,12 @@ jobs: run: rustup component add llvm-tools-preview - name: "Install cargo nextest" - uses: taiki-e/install-action@055f5df8c3f65ea01cd41e9dc855becd88953486 # v2.75.18 + uses: taiki-e/install-action@cf525cb33f51aca27cd6fa02034117ab963ff9f1 # v2.75.22 with: tool: cargo-nextest - name: "Install cargo-llvm-cov" - uses: taiki-e/install-action@055f5df8c3f65ea01cd41e9dc855becd88953486 # v2.75.18 + uses: taiki-e/install-action@cf525cb33f51aca27cd6fa02034117ab963ff9f1 # v2.75.22 with: tool: cargo-llvm-cov @@ -370,12 +370,12 @@ jobs: run: rustup component add llvm-tools-preview - name: "Install cargo nextest" - uses: taiki-e/install-action@055f5df8c3f65ea01cd41e9dc855becd88953486 # v2.75.18 + uses: taiki-e/install-action@cf525cb33f51aca27cd6fa02034117ab963ff9f1 # v2.75.22 with: tool: cargo-nextest - name: "Install cargo-llvm-cov" - uses: taiki-e/install-action@055f5df8c3f65ea01cd41e9dc855becd88953486 # v2.75.18 + uses: taiki-e/install-action@cf525cb33f51aca27cd6fa02034117ab963ff9f1 # v2.75.22 with: tool: cargo-llvm-cov @@ -436,12 +436,12 @@ jobs: run: rustup component add llvm-tools-preview - name: "Install cargo nextest" - uses: taiki-e/install-action@055f5df8c3f65ea01cd41e9dc855becd88953486 # v2.75.18 + uses: taiki-e/install-action@cf525cb33f51aca27cd6fa02034117ab963ff9f1 # v2.75.22 with: tool: cargo-nextest - name: "Install cargo-llvm-cov" - uses: taiki-e/install-action@055f5df8c3f65ea01cd41e9dc855becd88953486 # v2.75.18 + uses: taiki-e/install-action@cf525cb33f51aca27cd6fa02034117ab963ff9f1 # v2.75.22 with: tool: cargo-llvm-cov @@ -509,12 +509,12 @@ jobs: run: rustup component add llvm-tools-preview - name: "Install cargo nextest" - uses: taiki-e/install-action@055f5df8c3f65ea01cd41e9dc855becd88953486 # v2.75.18 + uses: taiki-e/install-action@cf525cb33f51aca27cd6fa02034117ab963ff9f1 # v2.75.22 with: tool: cargo-nextest - name: "Install cargo-llvm-cov" - uses: taiki-e/install-action@055f5df8c3f65ea01cd41e9dc855becd88953486 # v2.75.18 + uses: taiki-e/install-action@cf525cb33f51aca27cd6fa02034117ab963ff9f1 # v2.75.22 with: tool: cargo-llvm-cov @@ -564,7 +564,7 @@ jobs: - name: "Install Ruby" if: ${{ contains(format(' {0} ', matrix.languages), ' ruby ') }} - uses: ruby/setup-ruby@7372622e62b60b3cb750dcd2b9e32c247ffec26a # v1.302.0 + uses: ruby/setup-ruby@c4e5b1316158f92e3d49443a9d58b31d25ac0f8f # v1.306.0 with: ruby-version: ${{ env.RUBY_VERSION }} @@ -582,7 +582,7 @@ jobs: - name: "Install Dart" if: ${{ contains(format(' {0} ', matrix.languages), ' dart ') }} - uses: dart-lang/setup-dart@0a8a0fc875eb934c15d08629302413c671d3f672 # v1.6.5 + uses: dart-lang/setup-dart@65eb853c7ba17dde3be364c3d2858773e7144260 # v1.7.2 with: sdk: ${{ env.DART_VERSION }} @@ -595,7 +595,7 @@ jobs: - name: "Install Julia" if: ${{ contains(format(' {0} ', matrix.languages), ' julia ') }} - uses: julia-actions/setup-julia@4a12c5f801ca5ef0458bba44687563ef276522dd # v3.0.0 + uses: julia-actions/setup-julia@f6f565d9f7cf12f53dc8045742460d6260ad3b39 # v3.0.1 with: version: ${{ env.JULIA_VERSION }} diff --git a/.github/workflows/performance.yml b/.github/workflows/performance.yml index 9df57a5b4..066cff8a9 100644 --- a/.github/workflows/performance.yml +++ b/.github/workflows/performance.yml @@ -35,7 +35,7 @@ jobs: - uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1 with: save-if: ${{ inputs.save-rust-cache == 'true' }} - - uses: taiki-e/install-action@055f5df8c3f65ea01cd41e9dc855becd88953486 # v2.75.18 + - uses: taiki-e/install-action@cf525cb33f51aca27cd6fa02034117ab963ff9f1 # v2.75.22 with: tool: cargo-bloat @@ -152,7 +152,7 @@ jobs: cargo build --profile profiling && mv target/profiling/prek "$HYPERFINE_BIN_DIR/$HYPERFINE_HEAD_BINARY" - name: Install hyperfine - uses: taiki-e/install-action@055f5df8c3f65ea01cd41e9dc855becd88953486 # v2.75.18 + uses: taiki-e/install-action@cf525cb33f51aca27cd6fa02034117ab963ff9f1 # v2.75.22 with: tool: hyperfine From 8c9761a523bcb180ff35fcfcd8e85184f87eaceb Mon Sep 17 00:00:00 2001 From: Jo <10510431+j178@users.noreply.github.com> Date: Mon, 4 May 2026 17:09:53 +0800 Subject: [PATCH 18/23] Bump rand to 0.9.4 (#2040) Bumps the locked transitive rand 0.9.x dependency from 0.9.2 to 0.9.4. Validated with cargo check. --- Cargo.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 221375f08..cb9bc5103 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2314,7 +2314,7 @@ dependencies = [ "bytes", "getrandom 0.3.4", "lru-slab", - "rand 0.9.2", + "rand 0.9.4", "ring", "rustc-hash", "rustls", @@ -2363,9 +2363,9 @@ checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" [[package]] name = "rand" -version = "0.9.2" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" +checksum = "44c5af06bb1b7d3216d91932aed5265164bf384dc89cd6ba05cf59a35f5f76ea" dependencies = [ "rand_chacha", "rand_core 0.9.5", From 1bf54f5fa9638ad66a7d0b160170da75de1eec81 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 4 May 2026 17:17:49 +0800 Subject: [PATCH 19/23] Update Rust crate serde-saphyr to 0.0.25 (#2036) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR contains the following updates: | Package | Type | Update | Change | |---|---|---|---| | [serde-saphyr](https://redirect.github.com/bourumir-wyngs/serde-saphyr) | workspace.dependencies | patch | `0.0.23` → `0.0.25` | --- ### Release Notes
bourumir-wyngs/serde-saphyr (serde-saphyr) ### [`v0.0.25`](https://redirect.github.com/bourumir-wyngs/serde-saphyr/releases/tag/0.0.25): Maintenance release [Compare Source](https://redirect.github.com/bourumir-wyngs/serde-saphyr/compare/0.0.24...0.0.25) - Fixed deserialization bug ([#​100](https://redirect.github.com/bourumir-wyngs/serde-saphyr/issues/100)) where mixing tagged and #\[serde(untagged)] enum variants caused YAML tags to be ignored, leading to incorrect or failed variant resolution. - Rewritten unit test (ser\_coverage\_boost.rs) that was triggering the false positive Socket alert (it never ever tried to access the network) - Fixed taking numbers with preceding or trailing underscores as valid. `100000` is valid and `1000_000` also, but `_10`, `10_` are no longer. This is consistent with the serializer's auto-quoting policies. - Publishing to crates.io now uses a trusted publishing workflow. ### [`v0.0.24`](https://redirect.github.com/bourumir-wyngs/serde-saphyr/releases/tag/0.0.24): - remove heavy regex crate [Compare Source](https://redirect.github.com/bourumir-wyngs/serde-saphyr/compare/0.0.23...0.0.24) - Regex dependency is now **removed** using much lighter custom code. Regex was only used to detect numeric-looking strings that deserializer needs to quote (serde-saphyr itself does not need this, done for compatibility with other YAML readers). - Comment position can now be changed between **right** from the item the comment describes (default), or **above** the item it describes. Some teams have rules that comments must be above the items they describe, while numerous short comments look better in-line on the right. - Direct instantiation of parameter structures is not yet fully disabled, but since this release, such code emits **deprecation warnings**. We need to migrate to macros because adding any field to the public structure is formally a breaking change unless it is` #[non_exhaustive]`, but then it cannot be instantiated, listing fields at all. Use `options! { key: value, key2: value2 }` macro. After the 1.0.0 release, we still want to keep adding new options without a "major release".
--- ### Configuration 📅 **Schedule**: (UTC) - Branch creation - Between 12:00 AM and 03:59 AM, only on Monday (`* 0-3 * * 1`) - Automerge - At any time (no schedule defined) 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. 🔕 **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR was generated by [Mend Renovate](https://mend.io/renovate/). View the [repository job log](https://developer.mend.io/github/j178/prek). --------- Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: Jo <10510431+j178@users.noreply.github.com> --- Cargo.lock | 5 ++--- Cargo.toml | 2 +- crates/prek/src/hooks/pre_commit_hooks/check_yaml.rs | 8 +++----- 3 files changed, 6 insertions(+), 9 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index cb9bc5103..309d47bab 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2757,9 +2757,9 @@ dependencies = [ [[package]] name = "serde-saphyr" -version = "0.0.23" +version = "0.0.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09fbdfe7a27a1b1633dfc0c4c8e65940b8d819c5ddb9cca48ebc3223b00c8b14" +checksum = "75e214449d107a81daf1453eb46c9314457660509534883e82db6faca2034a8a" dependencies = [ "ahash", "annotate-snippets", @@ -2768,7 +2768,6 @@ dependencies = [ "getrandom 0.3.4", "nohash-hasher", "num-traits", - "regex", "saphyr-parser-bw", "serde", "smallvec", diff --git a/Cargo.toml b/Cargo.toml index a5c26bbbd..17cbb8fd3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -83,7 +83,7 @@ serde_json = { version = "1.0.132", features = [ "unbounded_depth", ] } serde_stacker = { version = "0.1.12" } -serde-saphyr = { version = "0.0.23", default-features = false, features = [ +serde-saphyr = { version = "0.0.25", default-features = false, features = [ "deserialize", "serialize", ] } diff --git a/crates/prek/src/hooks/pre_commit_hooks/check_yaml.rs b/crates/prek/src/hooks/pre_commit_hooks/check_yaml.rs index c93065388..f2c67a788 100644 --- a/crates/prek/src/hooks/pre_commit_hooks/check_yaml.rs +++ b/crates/prek/src/hooks/pre_commit_hooks/check_yaml.rs @@ -42,16 +42,14 @@ async fn check_file( return Ok((0, Vec::new())); } - let options = serde_saphyr::Options { - budget: Some(serde_saphyr::Budget { + let options = serde_saphyr::options! { + budget: serde_saphyr::budget! { // `check-yaml` is a syntax/structure validator, not a service parsing // untrusted YAML at runtime. Keep the absolute caps, but allow // high-reuse anchors that are common in compose-style files. enforce_alias_anchor_ratio: false, - ..Default::default() - }), + }, ignore_binary_tag_for_string: true, - ..Default::default() }; if allow_multi_docs { if let Err(e) = serde_saphyr::from_slice_multiple_with_options::( From 8af3054dc690fd06fe91b2b0c0ca4fe8e4418051 Mon Sep 17 00:00:00 2001 From: Jo <10510431+j178@users.noreply.github.com> Date: Mon, 4 May 2026 21:32:18 +0800 Subject: [PATCH 20/23] Pass commit message file to workspace hooks (#2043) Workspace `commit-msg` and `prepare-commit-msg` hooks now receive the Git message file as hook input for every matching project instead of losing it during workspace file filtering. This keeps normal workspace file ownership in `FileFilter`, while message-stage hook input is resolved once and converted to a project-relative argument at run time. Fixes #1194, Fixes #2042 --- crates/prek/src/cli/run/filter.rs | 62 ++++++++++++++++++++----- crates/prek/src/cli/run/mod.rs | 2 +- crates/prek/src/cli/run/run.rs | 69 ++++++++++++++++++++++------ crates/prek/tests/hook_impl.rs | 75 +++++++++++++++++++++++++++++++ 4 files changed, 182 insertions(+), 26 deletions(-) diff --git a/crates/prek/src/cli/run/filter.rs b/crates/prek/src/cli/run/filter.rs index ac88b8c05..371dce02e 100644 --- a/crates/prek/src/cli/run/filter.rs +++ b/crates/prek/src/cli/run/filter.rs @@ -225,10 +225,15 @@ impl CollectOptions { } } -/// Get all filenames to run hooks on. -/// Returns a list of file paths relative to the workspace root. -#[instrument(level = "trace", skip_all)] -pub(crate) async fn collect_files(root: &Path, opts: CollectOptions) -> Result> { +pub(crate) enum RunInput { + /// File paths relative to the workspace root. + Files(Vec), + /// Absolute path to the Git message file passed by `commit-msg` and `prepare-commit-msg`. + MessageFile(PathBuf), +} + +/// Get hook input for the selected stage. +pub(crate) async fn collect_run_input(root: &Path, opts: CollectOptions) -> Result { let CollectOptions { hook_stage, from_ref, @@ -239,6 +244,47 @@ pub(crate) async fn collect_files(root: &Path, opts: CollectOptions) -> Result Result> { + match collect_run_input(root, opts).await? { + RunInput::Files(files) => Ok(files), + // This compatibility API can only return workspace-relative files. + // Git message files are hook arguments, not workspace files, and are + // handled through `RunInput` by the main runner. + RunInput::MessageFile(_) => Ok(vec![]), + } +} + +#[allow(clippy::too_many_arguments)] +#[instrument(level = "trace", skip_all)] +async fn collect_workspace_files( + root: &Path, + hook_stage: Stage, + from_ref: Option, + to_ref: Option, + all_files: bool, + files: Vec, + directories: Vec, +) -> Result> { let git_root = GIT_ROOT.as_ref()?; // The workspace root relative to the git root. @@ -259,7 +305,6 @@ pub(crate) async fn collect_files(root: &Path, opts: CollectOptions) -> Result, directories: Vec, - commit_msg_filename: Option, ) -> Result> { if !hook_stage.operate_on_files() { return Ok(vec![]); } - if hook_stage == Stage::PrepareCommitMsg || hook_stage == Stage::CommitMsg { - let path = commit_msg_filename.expect("commit_msg_filename should be set"); - let path = adjust_relative_path(&path, git_root)?; - return Ok(vec![path]); - } - if let (Some(from_ref), Some(to_ref)) = (from_ref, to_ref) { let files = git::get_changed_files(&from_ref, &to_ref, workspace_root).await?; debug!( diff --git a/crates/prek/src/cli/run/mod.rs b/crates/prek/src/cli/run/mod.rs index 0fe753380..77f7a7615 100644 --- a/crates/prek/src/cli/run/mod.rs +++ b/crates/prek/src/cli/run/mod.rs @@ -1,4 +1,4 @@ -pub(crate) use filter::{CollectOptions, FileFilter, collect_files}; +pub(crate) use filter::{CollectOptions, FileFilter, RunInput, collect_files, collect_run_input}; pub(crate) use run::{install_hooks, run}; pub(crate) use selector::{SelectorSource, Selectors}; diff --git a/crates/prek/src/cli/run/run.rs b/crates/prek/src/cli/run/run.rs index b335f901a..2f96e20e5 100644 --- a/crates/prek/src/cli/run/run.rs +++ b/crates/prek/src/cli/run/run.rs @@ -1,6 +1,6 @@ use std::fmt::Write as _; use std::io::Write as _; -use std::path::PathBuf; +use std::path::{Path, PathBuf}; use std::rc::Rc; use std::sync::{Arc, LazyLock}; @@ -19,7 +19,7 @@ use unicode_width::UnicodeWidthStr; use crate::cli::reporter::{HookInitReporter, HookInstallReporter, HookRunReporter}; use crate::cli::run::keeper::WorkTreeKeeper; -use crate::cli::run::{CollectOptions, FileFilter, Selectors, collect_files}; +use crate::cli::run::{CollectOptions, FileFilter, RunInput, Selectors, collect_run_input}; use crate::cli::{ExitStatus, RunExtraArgs}; use crate::config::{Language, PassFilenames, Stage}; use crate::fs::CWD; @@ -29,7 +29,7 @@ use crate::printer::Printer; use crate::run::{CONCURRENCY, USE_COLOR}; use crate::store::Store; use crate::workspace::{Project, Workspace}; -use crate::{git, warn_user}; +use crate::{fs, git, warn_user}; #[allow(clippy::too_many_arguments, clippy::fn_params_excessive_bools)] pub(crate) async fn run( @@ -177,7 +177,7 @@ pub(crate) async fn run( set_env_vars(from_ref.as_ref(), to_ref.as_ref(), &extra_args); - let filenames = collect_files( + let input = collect_run_input( workspace.root(), CollectOptions { hook_stage, @@ -203,7 +203,7 @@ pub(crate) async fn run( run_hooks( &workspace, &installed_hooks, - filenames, + input, store, show_diff_on_failure, fail_fast, @@ -570,12 +570,55 @@ impl StatusPrinter { } } +enum ProjectHookInput<'a> { + Files(FileFilter<'a>), + MessageFile(PathBuf), +} + +impl<'a> ProjectHookInput<'a> { + fn new( + input: &'a RunInput, + project: &Project, + consumed_files: Option<&mut FxHashSet<&'a Path>>, + ) -> Result { + match input { + RunInput::Files(files) => Ok(Self::Files(FileFilter::for_project( + files.iter(), + project, + consumed_files, + ))), + RunInput::MessageFile(path) => Ok(Self::MessageFile(fs::normalize_path( + fs::relative_to(path, project.path())?, + ))), + } + } + + fn len(&self) -> usize { + match self { + Self::Files(filter) => filter.len(), + Self::MessageFile(_) => 1, + } + } + + fn for_hook(&self, hook: &Hook) -> Vec<&Path> { + match self { + Self::Files(filter) => filter.for_hook(hook), + Self::MessageFile(path) => { + // `commit-msg` and `prepare-commit-msg` receive Git's message file, which is not + // a workspace file. The `files`/`exclude`/`types` filters are workspace-file + // selectors, so they do not apply to this hook argument. + vec![path.as_path()] + } + } + } +} + /// Run all hooks. #[allow(clippy::fn_params_excessive_bools)] async fn run_hooks( workspace: &Workspace, hooks: &[InstalledHook], - filenames: Vec, + input: RunInput, store: &Store, show_diff_on_failure: bool, fail_fast: Option, @@ -609,14 +652,14 @@ async fn run_hooks( let mut consumed_files = FxHashSet::default(); 'outer: for project in workspace.all_projects() { - let filter = FileFilter::for_project(filenames.iter(), project, Some(&mut consumed_files)); + let project_input = ProjectHookInput::new(&input, project, Some(&mut consumed_files))?; let Some(mut hooks) = project_to_hooks.remove(project) else { continue; }; trace!( "Files for project `{project}` after filtered: {}", - filter.len() + project_input.len() ); // Sort hooks by priority (lower number means higher priority). @@ -641,7 +684,7 @@ async fn run_hooks( for group_range in PriorityGroupRanges::new(&hooks) { let group_hooks = hooks[group_range].to_vec(); let mut group_results = - run_priority_group(group_hooks, &filter, store, dry_run, &reporter).await?; + run_priority_group(group_hooks, &project_input, store, dry_run, &reporter).await?; // Print results in a stable order (same order as config within the project). group_results.sort_unstable_by_key(|a| a.hook.idx); @@ -769,7 +812,7 @@ impl Iterator for PriorityGroupRanges<'_> { async fn run_priority_group( group_hooks: Vec, - filter: &FileFilter<'_>, + input: &ProjectHookInput<'_>, store: &Store, dry_run: bool, reporter: &HookRunReporter, @@ -784,7 +827,7 @@ async fn run_priority_group( let mut results = futures::stream::iter( group_hooks .into_iter() - .map(|hook| run_hook(hook, filter, store, dry_run, reporter)), + .map(|hook| run_hook(hook, input, store, dry_run, reporter)), ) .buffer_unordered(*CONCURRENCY); @@ -1000,12 +1043,12 @@ impl RunResult { async fn run_hook( hook: InstalledHook, - filter: &FileFilter<'_>, + input: &ProjectHookInput<'_>, store: &Store, dry_run: bool, reporter: &HookRunReporter, ) -> Result { - let mut filenames = filter.for_hook(&hook); + let mut filenames = input.for_hook(&hook); trace!( "Files for hook `{}` after filtered: {}", hook.id, diff --git a/crates/prek/tests/hook_impl.rs b/crates/prek/tests/hook_impl.rs index 8568301a9..7cb861316 100644 --- a/crates/prek/tests/hook_impl.rs +++ b/crates/prek/tests/hook_impl.rs @@ -570,6 +570,81 @@ fn workspace_hook_impl_root() -> anyhow::Result<()> { Ok(()) } +#[test] +fn workspace_commit_msg_hook_receives_message_file_for_each_project() -> anyhow::Result<()> { + let context = TestContext::new(); + context.init_project(); + + let config = indoc! {r#" + default_install_hook_types: + - commit-msg + repos: + - repo: local + hooks: + - id: commit-msg-args + name: Commit Msg Args + language: python + entry: python -c 'import os, pathlib, sys; print("cwd:", os.getcwd()); print("args:", sys.argv[1:]); assert len(sys.argv) == 2; assert pathlib.Path(sys.argv[1]).is_file()' + stages: [commit-msg] + always_run: true + verbose: true + "#}; + + context.setup_workspace(&["template"], config)?; + context.git_add("."); + + cmd_snapshot!(context.filters(), context.install(), @r" + success: true + exit_code: 0 + ----- stdout ----- + prek installed at `.git/hooks/commit-msg` + + ----- stderr ----- + "); + + let mut commit = git_cmd(context.work_dir()); + commit + .env(EnvVars::PREK_HOME, &**context.home_dir()) + .arg("commit") + .arg("-m") + .arg("feat: initial"); + + let filters = context + .filters() + .into_iter() + .chain([("[a-f0-9]{7}", "abc1234")]) + .collect::>(); + + cmd_snapshot!(filters, commit, @r" + success: true + exit_code: 0 + ----- stdout ----- + [master (root-commit) abc1234] feat: initial + 2 files changed, 24 insertions(+) + create mode 100644 .pre-commit-config.yaml + create mode 100644 template/.pre-commit-config.yaml + + ----- stderr ----- + Running hooks for `template`: + Commit Msg Args..........................................................Passed + - hook id: commit-msg-args + - duration: [TIME] + + cwd: [TEMP_DIR]/template + args: ['../.git/COMMIT_EDITMSG'] + + Running hooks for `.`: + Commit Msg Args..........................................................Passed + - hook id: commit-msg-args + - duration: [TIME] + + cwd: [TEMP_DIR]/ + args: ['.git/COMMIT_EDITMSG'] + "); + + Ok(()) +} + #[test] fn workspace_hook_impl_subdirectory() -> anyhow::Result<()> { let context = TestContext::new(); From c52833e9991584d03bcd7e2b6fc01fa43e1f0d09 Mon Sep 17 00:00:00 2001 From: Jo <10510431+j178@users.noreply.github.com> Date: Tue, 5 May 2026 13:11:02 +0800 Subject: [PATCH 21/23] Add global auto-update cooldown config (#2041) Adds a user-level global `prek.toml` and wires `auto-update.cooldown-days` into `prek auto-update` Closes #2032 Related #58 --- crates/prek-consts/src/env_vars.rs | 1 + crates/prek/src/cli/mod.rs | 10 +- crates/prek/src/main.rs | 8 +- crates/prek/src/settings.rs | 112 ++++++++++++++++++ crates/prek/tests/common/mod.rs | 22 ++++ crates/prek/tests/global_config.rs | 182 +++++++++++++++++++++++++++++ docs/configuration.md | 18 +++ docs/reference/cli.md | 4 +- docs/reference/configuration.md | 24 ++++ 9 files changed, 371 insertions(+), 10 deletions(-) create mode 100644 crates/prek/src/settings.rs create mode 100644 crates/prek/tests/global_config.rs diff --git a/crates/prek-consts/src/env_vars.rs b/crates/prek-consts/src/env_vars.rs index cc830dddd..b18f1a40f 100644 --- a/crates/prek-consts/src/env_vars.rs +++ b/crates/prek-consts/src/env_vars.rs @@ -35,6 +35,7 @@ impl EnvVars { // PREK internal environment variables pub const PREK_INTERNAL__TEST_DIR: &'static str = "PREK_INTERNAL__TEST_DIR"; + pub const PREK_INTERNAL__USER_CONFIG_PATH: &'static str = "PREK_INTERNAL__USER_CONFIG_PATH"; pub const PREK_INTERNAL__SORT_FILENAMES: &'static str = "PREK_INTERNAL__SORT_FILENAMES"; pub const PREK_INTERNAL__SKIP_POST_CHECKOUT: &'static str = "PREK_INTERNAL__SKIP_POST_CHECKOUT"; pub const PREK_INTERNAL__RUN_ORIGINAL_PRE_COMMIT: &'static str = diff --git a/crates/prek/src/cli/mod.rs b/crates/prek/src/cli/mod.rs index 366fb2c3f..b3fccd0d7 100644 --- a/crates/prek/src/cli/mod.rs +++ b/crates/prek/src/cli/mod.rs @@ -757,14 +757,10 @@ pub(crate) struct AutoUpdateArgs { /// Minimum release age (in days) required for a version to be eligible. /// /// The age is computed from the tag creation timestamp for annotated tags, or from the tagged commit timestamp for lightweight tags. + /// Defaults to `auto_update.cooldown_days` in the global config, or `0` when unset. /// A value of `0` disables this check. - #[arg( - long, - value_name = "DAYS", - default_value_t = 0, - conflicts_with = "bleeding_edge" - )] - pub(crate) cooldown_days: u8, + #[arg(long, value_name = "DAYS", conflicts_with = "bleeding_edge")] + pub(crate) cooldown_days: Option, } #[derive(Debug, Args)] diff --git a/crates/prek/src/main.rs b/crates/prek/src/main.rs index 744b60b5a..b56859acf 100644 --- a/crates/prek/src/main.rs +++ b/crates/prek/src/main.rs @@ -26,6 +26,7 @@ use crate::cli::{ use crate::cli::{SelfCommand, SelfNamespace, SelfUpdateArgs}; use crate::printer::Printer; use crate::run::USE_COLOR; +use crate::settings::{AutoUpdateSettings, FilesystemOptions}; use crate::store::Store; mod archive; @@ -49,6 +50,7 @@ mod resource_limit; mod run; #[cfg(feature = "schemars")] mod schema; +mod settings; mod store; mod version; mod warnings; @@ -373,6 +375,10 @@ async fn run(cli: Cli) -> Result { } Command::SampleConfig(args) => cli::sample_config(args.file.into(), args.format, printer), Command::AutoUpdate(args) => { + let filesystem = FilesystemOptions::user()?; + let settings = AutoUpdateSettings::resolve(&args, filesystem.as_ref()); + show_settings!(settings); + cli::auto_update( &store, cli.globals.config, @@ -388,7 +394,7 @@ async fn run(cli: Cli) -> Result { args.jobs, args.dry_run || args.check, args.exit_code || args.check, - args.cooldown_days, + settings.cooldown_days, printer, ) .await diff --git a/crates/prek/src/settings.rs b/crates/prek/src/settings.rs new file mode 100644 index 000000000..f1e5a7d43 --- /dev/null +++ b/crates/prek/src/settings.rs @@ -0,0 +1,112 @@ +use std::io::ErrorKind; +use std::ops::Deref; +use std::path::{Path, PathBuf}; + +use anyhow::{Context, Result}; +use etcetera::BaseStrategy; +use prek_consts::env_vars::EnvVars; +use serde::Deserialize; + +use crate::cli::AutoUpdateArgs; + +fn user_config_path() -> Option { + if let Some(path) = EnvVars::var_os(EnvVars::PREK_INTERNAL__USER_CONFIG_PATH) { + return Some(PathBuf::from(path)); + } + + etcetera::choose_base_strategy() + .ok() + .map(|strategy| strategy.config_dir().join("prek").join("prek.toml")) +} + +/// Options loaded from a user-level `prek.toml` file. +#[derive(Debug, Clone)] +pub(crate) struct FilesystemOptions(Options); + +impl FilesystemOptions { + /// Load user-level options from the platform config directory. + pub(crate) fn user() -> Result> { + let Some(path) = user_config_path() else { + tracing::trace!( + "Skipping global config lookup because no platform config directory was found" + ); + return Ok(None); + }; + + tracing::trace!(path = %path.display(), "Searching for global config"); + Self::from_file(&path) + } + + fn from_file(path: &Path) -> Result> { + let content = match fs_err::read_to_string(path) { + Ok(content) => { + tracing::debug!(path = %path.display(), "Read global config"); + content + } + Err(err) + if matches!( + err.kind(), + ErrorKind::NotFound | ErrorKind::NotADirectory | ErrorKind::PermissionDenied + ) => + { + tracing::trace!( + path = %path.display(), + "Global config not found or inaccessible, skipping" + ); + return Ok(None); + } + Err(err) => { + return Err(err) + .with_context(|| format!("Failed to read global config `{}`", path.display())); + } + }; + + toml::from_str(&content) + .map(Self) + .map(Some) + .with_context(|| format!("Failed to parse global config `{}`", path.display())) + } +} + +impl Deref for FilesystemOptions { + type Target = Options; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +/// Options as represented in the global `prek.toml` file. +#[derive(Debug, Clone, Default, Deserialize)] +#[serde(default, rename_all = "snake_case")] +pub(crate) struct Options { + auto_update: Option, +} + +/// Options for the `auto-update` command. +#[derive(Debug, Clone, Default, Deserialize)] +#[serde(default, rename_all = "snake_case")] +struct AutoUpdateOptions { + cooldown_days: Option, +} + +/// Resolved settings for the `auto-update` command. +#[derive(Debug, Clone, Copy)] +pub(crate) struct AutoUpdateSettings { + pub(crate) cooldown_days: u8, +} + +impl AutoUpdateSettings { + pub(crate) fn resolve(args: &AutoUpdateArgs, filesystem: Option<&FilesystemOptions>) -> Self { + Self { + cooldown_days: args + .cooldown_days + .or_else(|| { + filesystem + .and_then(|fs| fs.auto_update.as_ref()) + .and_then(|au| au.cooldown_days) + }) + .unwrap_or_default(), + } + } +} diff --git a/crates/prek/tests/common/mod.rs b/crates/prek/tests/common/mod.rs index 8350a1e3e..2ec907f11 100644 --- a/crates/prek/tests/common/mod.rs +++ b/crates/prek/tests/common/mod.rs @@ -169,6 +169,11 @@ impl TestContext { cmd }; + cmd.env( + EnvVars::PREK_INTERNAL__USER_CONFIG_PATH, + self.user_config_path().path(), + ); + // Disable git autocrlf to avoid line ending issues in tests. cmd.env("GIT_CONFIG_COUNT", "1") .env("GIT_CONFIG_KEY_0", "core.autocrlf") @@ -177,6 +182,23 @@ impl TestContext { cmd } + fn user_config_path(&self) -> ChildPath { + self.home_dir + .child("config") + .child("prek") + .child("prek.toml") + } + + pub fn write_user_config(&self, content: &str) { + let config_dir = self.home_dir.child("config").child("prek"); + config_dir + .create_dir_all() + .expect("Failed to create user config directory"); + self.user_config_path() + .write_str(content) + .expect("Failed to write user config"); + } + pub fn run(&self) -> Command { let mut command = self.command(); command.arg("run"); diff --git a/crates/prek/tests/global_config.rs b/crates/prek/tests/global_config.rs new file mode 100644 index 000000000..7c5ff328f --- /dev/null +++ b/crates/prek/tests/global_config.rs @@ -0,0 +1,182 @@ +use crate::common::{TestContext, cmd_snapshot}; + +mod common; + +#[test] +fn global_config_missing_file_uses_defaults() { + let context = TestContext::new(); + + cmd_snapshot!(context.filters(), context.auto_update().arg("--show-settings"), @" + success: true + exit_code: 0 + ----- stdout ----- + GlobalArgs { + config: None, + cd: None, + color: Auto, + refresh: false, + help: (), + no_progress: false, + quiet: 0, + verbose: 0, + log_file: None, + no_log_file: false, + version: (), + show_settings: true, + } + AutoUpdateSettings { + cooldown_days: 0, + } + + ----- stderr ----- + "); +} + +#[test] +fn global_config_applies_cooldown_days() { + let context = TestContext::new(); + context.write_user_config(indoc::indoc! {r" + [auto_update] + cooldown_days = 3 + "}); + + cmd_snapshot!(context.filters(), context.auto_update().arg("--show-settings"), @" + success: true + exit_code: 0 + ----- stdout ----- + GlobalArgs { + config: None, + cd: None, + color: Auto, + refresh: false, + help: (), + no_progress: false, + quiet: 0, + verbose: 0, + log_file: None, + no_log_file: false, + version: (), + show_settings: true, + } + AutoUpdateSettings { + cooldown_days: 3, + } + + ----- stderr ----- + "); +} + +#[test] +fn global_config_cli_args_override_file() { + let context = TestContext::new(); + context.write_user_config(indoc::indoc! {r" + [auto_update] + cooldown_days = 3 + "}); + + cmd_snapshot!( + context.filters(), + context + .auto_update() + .arg("--show-settings") + .arg("--cooldown-days") + .arg("0"), + @" + success: true + exit_code: 0 + ----- stdout ----- + GlobalArgs { + config: None, + cd: None, + color: Auto, + refresh: false, + help: (), + no_progress: false, + quiet: 0, + verbose: 0, + log_file: None, + no_log_file: false, + version: (), + show_settings: true, + } + AutoUpdateSettings { + cooldown_days: 0, + } + + ----- stderr ----- + "); +} + +#[test] +fn global_config_ignores_unknown_options() { + let context = TestContext::new(); + context.write_user_config(indoc::indoc! {r#" + future_option = true + + [auto_update] + cooldown_days = 3 + future_option = "ignored" + "#}); + + cmd_snapshot!(context.filters(), context.auto_update().arg("--show-settings"), @" + success: true + exit_code: 0 + ----- stdout ----- + GlobalArgs { + config: None, + cd: None, + color: Auto, + refresh: false, + help: (), + no_progress: false, + quiet: 0, + verbose: 0, + log_file: None, + no_log_file: false, + version: (), + show_settings: true, + } + AutoUpdateSettings { + cooldown_days: 3, + } + + ----- stderr ----- + "); +} + +#[test] +fn global_config_invalid_file_reports_parse_error() { + let context = TestContext::new(); + context.write_user_config(indoc::indoc! {r#" + [auto_update] + cooldown_days = "soon" + "#}); + + cmd_snapshot!(context.filters(), context.auto_update().arg("--show-settings"), @r#" + success: false + exit_code: 2 + ----- stdout ----- + GlobalArgs { + config: None, + cd: None, + color: Auto, + refresh: false, + help: (), + no_progress: false, + quiet: 0, + verbose: 0, + log_file: None, + no_log_file: false, + version: (), + show_settings: true, + } + + ----- stderr ----- + error: Failed to parse global config `[HOME]/config/prek/prek.toml` + caused by: TOML parse error at line 2, column 17 + | + 2 | cooldown_days = "soon" + | ^^^^^^ + invalid type: string "soon", expected u8 + "#); +} diff --git a/docs/configuration.md b/docs/configuration.md index d22a08dd1..2542df5c9 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -24,6 +24,24 @@ Both formats are first-class and will be supported long-term. They describe the - id: trailing-whitespace ``` +## Global configuration + +`prek` also reads an optional user-level global config from the platform config directory: + +- Linux and macOS: `~/.config/prek/prek.toml` (or `$XDG_CONFIG_HOME/prek/prek.toml` when `XDG_CONFIG_HOME` is set) +- Windows: `%APPDATA%\prek\prek.toml` + +This file is for user-level `prek` settings, not hook definitions. Project hooks still live in the project config files described below. + +The first supported global setting is the default cooldown for `prek auto-update`: + +```toml +[auto_update] +cooldown_days = 7 +``` + +`prek auto-update --cooldown-days ` overrides this value for a single command invocation. + ## Pre-commit compatibility `prek` is **fully compatible** with [`pre-commit`](https://pre-commit.com/) YAML configs, so your existing `.pre-commit-config.yaml` files work unchanged. diff --git a/docs/reference/cli.md b/docs/reference/cli.md index 2fbd6b776..06e1fe3cb 100644 --- a/docs/reference/cli.md +++ b/docs/reference/cli.md @@ -561,8 +561,8 @@ prek auto-update [OPTIONS]
  • never: Disables colored output
  • --config, -c config

    Path to alternate config file

    --cooldown-days days

    Minimum release age (in days) required for a version to be eligible.

    -

    The age is computed from the tag creation timestamp for annotated tags, or from the tagged commit timestamp for lightweight tags. A value of 0 disables this check.

    -

    [default: 0]

    --dry-run

    Do not write changes to the config file, only display what would be changed

    +

    The age is computed from the tag creation timestamp for annotated tags, or from the tagged commit timestamp for lightweight tags. Defaults to auto_update.cooldown_days in the global config, or 0 when unset. A value of 0 disables this check.

    +
    --dry-run

    Do not write changes to the config file, only display what would be changed

    --exclude-repo repo

    Do not update this repository. This option may be specified multiple times

    --exclude-tag pattern

    Ignore tags matching this glob pattern. This option may be specified multiple times.

    For example, use --exclude-tag nightly to skip a moving tag, or --exclude-tag '*-{alpha,beta,rc}*' to skip common prerelease tags.

    diff --git a/docs/reference/configuration.md b/docs/reference/configuration.md index 694d43875..0a1846dac 100644 --- a/docs/reference/configuration.md +++ b/docs/reference/configuration.md @@ -2,6 +2,30 @@ This page documents the configuration keys that `prek` understands. +## Global config file + +`prek` reads an optional user-level global config from: + +- Linux and macOS: `~/.config/prek/prek.toml` (or `$XDG_CONFIG_HOME/prek/prek.toml` when `XDG_CONFIG_HOME` is set) +- Windows: `%APPDATA%\prek\prek.toml` + +This file stores user-level `prek` settings and does not define project hooks. + +### `auto_update.cooldown_days` + +Default cooldown for `prek auto-update`. + +- Type: integer days +- Default: `0` +- CLI override: `prek auto-update --cooldown-days ` + +```toml +[auto_update] +cooldown_days = 7 +``` + +The age is computed from the tag creation timestamp for annotated tags, or from the tagged commit timestamp for lightweight tags. A value of `0` disables the cooldown check. + ## Top-level keys ### `repos` (required) From 5f94f6f8ea8e5df0fb6604b4b8ec63072e1dc8f3 Mon Sep 17 00:00:00 2001 From: Jo <10510431+j178@users.noreply.github.com> Date: Tue, 5 May 2026 13:27:19 +0800 Subject: [PATCH 22/23] Add project auto-update cooldown config (#2044) ## Summary Add project-level `auto_update.cooldown_days` support for `prek.toml` and `.pre-commit-config.yaml`. Closes #1765 --- crates/prek/src/cli/auto_update/mod.rs | 23 ++- crates/prek/src/cli/auto_update/source.rs | 37 ++++- crates/prek/src/cli/mod.rs | 4 +- crates/prek/src/config.rs | 10 ++ crates/prek/src/hook.rs | 1 + crates/prek/src/main.rs | 8 +- crates/prek/src/settings.rs | 14 +- ...prek__config__tests__language_version.snap | 1 + .../prek__config__tests__meta_hooks-5.snap | 1 + ...ests__numeric_rev_is_parsed_as_string.snap | 1 + .../prek__config__tests__parse_hooks-3.snap | 1 + .../prek__config__tests__parse_repos-3.snap | 1 + .../prek__config__tests__parse_repos-4.snap | 1 + .../prek__config__tests__parse_repos-6.snap | 1 + .../prek__config__tests__parse_repos.snap | 1 + ...g__tests__read_config_with_merge_keys.snap | 1 + ...s__read_config_with_nested_merge_keys.snap | 1 + ...prek__config__tests__read_toml_config.snap | 1 + ...prek__config__tests__read_yaml_config.snap | 1 + crates/prek/tests/auto_update.rs | 105 ++++++++++++++ crates/prek/tests/global_config.rs | 137 ++---------------- docs/configuration.md | 22 ++- docs/reference/cli.md | 2 +- docs/reference/configuration.md | 35 ++++- prek.schema.json | 15 ++ 25 files changed, 262 insertions(+), 163 deletions(-) diff --git a/crates/prek/src/cli/auto_update/mod.rs b/crates/prek/src/cli/auto_update/mod.rs index fd02f795f..3e0027c81 100644 --- a/crates/prek/src/cli/auto_update/mod.rs +++ b/crates/prek/src/cli/auto_update/mod.rs @@ -15,6 +15,7 @@ use crate::config::GlobPatterns; use crate::fs::CWD; use crate::printer::Printer; use crate::run::CONCURRENCY; +use crate::settings::FilesystemOptions; use crate::store::Store; use crate::workspace::{Project, Workspace}; @@ -54,6 +55,8 @@ struct RepoTarget<'a> { repo: &'a str, /// The currently configured `rev` for this target. current_rev: &'a str, + /// The resolved cooldown window to apply when selecting an update for this target. + cooldown_days: u8, /// The sorted hook ids that must still exist after updating this target. required_hook_ids: Vec<&'a str>, /// Every config usage that shares this exact `repo + rev + hook set`. @@ -325,19 +328,21 @@ pub(crate) async fn auto_update( jobs: usize, dry_run: bool, exit_code: bool, - cooldown_days: u8, + cooldown_days: Option, + filesystem: Option, printer: Printer, ) -> Result { - let tag_filters = - TagFilters::new(include_tag, exclude_tag, repo_include_tag, repo_exclude_tag)?; let workspace_root = Workspace::find_root(config.as_deref(), &CWD)?; // TODO: support selectors? let selectors = Selectors::default(); let workspace = Workspace::discover(store, workspace_root, config, Some(&selectors), true)?; + + let tag_filters = + TagFilters::new(include_tag, exclude_tag, repo_include_tag, repo_exclude_tag)?; let jobs = if jobs == 0 { *CONCURRENCY } else { jobs }; let reporter = AutoUpdateReporter::new(printer); - let repo_sources = collect_repo_sources(&workspace)?; + let repo_sources = collect_repo_sources(&workspace, cooldown_days, filesystem.as_ref())?; let sources = repo_sources.iter().filter(|repo_source| { (filter_repos.is_empty() || filter_repos.iter().any(|repo| repo == repo_source.repo)) && !exclude_repos.iter().any(|repo| repo == repo_source.repo) @@ -345,14 +350,8 @@ pub(crate) async fn auto_update( let outcomes: Vec> = futures::stream::iter(sources) .map(async |repo_source| { let progress = reporter.on_update_start(repo_source.repo); - let result = evaluate_repo_source( - repo_source, - bleeding_edge, - freeze, - cooldown_days, - &tag_filters, - ) - .await; + let result = + evaluate_repo_source(repo_source, bleeding_edge, freeze, &tag_filters).await; reporter.on_update_complete(progress); result }) diff --git a/crates/prek/src/cli/auto_update/source.rs b/crates/prek/src/cli/auto_update/source.rs index 9eef595a2..7aabd80c3 100644 --- a/crates/prek/src/cli/auto_update/source.rs +++ b/crates/prek/src/cli/auto_update/source.rs @@ -16,14 +16,32 @@ use crate::cli::auto_update::{ }; use crate::config::{Repo, looks_like_sha}; use crate::fs::Simplified; +use crate::settings::{AutoUpdateSettings, FilesystemOptions}; use crate::workspace::Workspace; +type RepoTargetKey<'a> = (&'a str, Vec<&'a str>, u8); +type RepoTargetsByKey<'a> = FxHashMap, RepoTarget<'a>>; +type RepoSourcesByRepo<'a> = FxHashMap<&'a str, RepoTargetsByKey<'a>>; + /// Collects the configured remote repos grouped by fetch source, revision, and hook set. -pub(super) fn collect_repo_sources(workspace: &Workspace) -> Result>> { - let mut repo_sources: FxHashMap<&str, FxHashMap<(&str, Vec<&str>), RepoTarget<'_>>> = - FxHashMap::default(); +pub(super) fn collect_repo_sources<'a>( + workspace: &'a Workspace, + cli_cooldown_days: Option, + filesystem: Option<&FilesystemOptions>, +) -> Result>> { + let mut repo_sources: RepoSourcesByRepo<'a> = FxHashMap::default(); for project in workspace.projects() { + let settings = AutoUpdateSettings::resolve( + cli_cooldown_days, + filesystem, + project + .config() + .auto_update + .as_ref() + .and_then(|options| options.cooldown_days), + ); + let cooldown_days = settings.cooldown_days; let remote_count = project .config() .repos @@ -64,10 +82,15 @@ pub(super) fn collect_repo_sources(workspace: &Workspace) -> Result Result( repo_source: &'a RepoSource<'a>, bleeding_edge: bool, freeze: bool, - cooldown_days: u8, tag_filters: &TagFilters, ) -> Result>> { let tmp_dir = tempfile::tempdir()?; @@ -214,7 +237,6 @@ pub(super) async fn evaluate_repo_source<'a>( target, bleeding_edge, freeze, - cooldown_days, &tag_timestamps, &update_tag_timestamps, ) @@ -232,7 +254,6 @@ async fn evaluate_repo_target<'a>( target: &'a RepoTarget<'a>, bleeding_edge: bool, freeze: bool, - cooldown_days: u8, tag_timestamps: &[TagTimestamp], update_tag_timestamps: &[TagTimestamp], ) -> Result> { @@ -252,7 +273,7 @@ async fn evaluate_repo_target<'a>( repo_path, target.current_rev, bleeding_edge, - cooldown_days, + target.cooldown_days, update_tag_timestamps, ) .await?; diff --git a/crates/prek/src/cli/mod.rs b/crates/prek/src/cli/mod.rs index b3fccd0d7..2638f5651 100644 --- a/crates/prek/src/cli/mod.rs +++ b/crates/prek/src/cli/mod.rs @@ -757,8 +757,8 @@ pub(crate) struct AutoUpdateArgs { /// Minimum release age (in days) required for a version to be eligible. /// /// The age is computed from the tag creation timestamp for annotated tags, or from the tagged commit timestamp for lightweight tags. - /// Defaults to `auto_update.cooldown_days` in the global config, or `0` when unset. - /// A value of `0` disables this check. + /// Defaults to `auto_update.cooldown_days` in the project or global config, or `0` when unset. + /// Valid values are `0` through `255`; `0` disables this check. #[arg(long, value_name = "DAYS", conflicts_with = "bleeding_edge")] pub(crate) cooldown_days: Option, } diff --git a/crates/prek/src/config.rs b/crates/prek/src/config.rs index d4f39eeba..8ef8e7a86 100644 --- a/crates/prek/src/config.rs +++ b/crates/prek/src/config.rs @@ -1117,6 +1117,14 @@ where }) } +/// Controls how `prek auto-update` selects eligible releases. +#[derive(Debug, Clone, Default, Deserialize)] +#[serde(default, rename_all = "snake_case")] +#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] +pub(crate) struct AutoUpdateOptions { + pub(crate) cooldown_days: Option, +} + // TODO: warn sensible regex #[derive(Debug, Clone, Deserialize)] #[serde(rename_all = "snake_case")] @@ -1129,6 +1137,8 @@ where schemars(extend("x-tombi-toml-version" = "v1.1.0")), )] pub(crate) struct Config { + /// Default settings for `prek auto-update` in this project. + pub auto_update: Option, pub repos: Vec, /// A list of `--hook-types` which will be used by default when running `prek install`. /// Default is `[pre-commit]`. diff --git a/crates/prek/src/hook.rs b/crates/prek/src/hook.rs index d0f5f47c9..464a8316b 100644 --- a/crates/prek/src/hook.rs +++ b/crates/prek/src/hook.rs @@ -921,6 +921,7 @@ mod tests { relative_path: "", idx: 0, config: Config { + auto_update: None, repos: [], default_install_hook_types: None, default_language_version: Some( diff --git a/crates/prek/src/main.rs b/crates/prek/src/main.rs index b56859acf..0b1ff8b3e 100644 --- a/crates/prek/src/main.rs +++ b/crates/prek/src/main.rs @@ -26,7 +26,7 @@ use crate::cli::{ use crate::cli::{SelfCommand, SelfNamespace, SelfUpdateArgs}; use crate::printer::Printer; use crate::run::USE_COLOR; -use crate::settings::{AutoUpdateSettings, FilesystemOptions}; +use crate::settings::FilesystemOptions; use crate::store::Store; mod archive; @@ -376,8 +376,7 @@ async fn run(cli: Cli) -> Result { Command::SampleConfig(args) => cli::sample_config(args.file.into(), args.format, printer), Command::AutoUpdate(args) => { let filesystem = FilesystemOptions::user()?; - let settings = AutoUpdateSettings::resolve(&args, filesystem.as_ref()); - show_settings!(settings); + show_settings!(args); cli::auto_update( &store, @@ -394,7 +393,8 @@ async fn run(cli: Cli) -> Result { args.jobs, args.dry_run || args.check, args.exit_code || args.check, - settings.cooldown_days, + args.cooldown_days, + filesystem, printer, ) .await diff --git a/crates/prek/src/settings.rs b/crates/prek/src/settings.rs index f1e5a7d43..ca7a84c0b 100644 --- a/crates/prek/src/settings.rs +++ b/crates/prek/src/settings.rs @@ -7,8 +7,6 @@ use etcetera::BaseStrategy; use prek_consts::env_vars::EnvVars; use serde::Deserialize; -use crate::cli::AutoUpdateArgs; - fn user_config_path() -> Option { if let Some(path) = EnvVars::var_os(EnvVars::PREK_INTERNAL__USER_CONFIG_PATH) { return Some(PathBuf::from(path)); @@ -97,14 +95,18 @@ pub(crate) struct AutoUpdateSettings { } impl AutoUpdateSettings { - pub(crate) fn resolve(args: &AutoUpdateArgs, filesystem: Option<&FilesystemOptions>) -> Self { + pub(crate) fn resolve( + cli_cooldown_days: Option, + filesystem: Option<&FilesystemOptions>, + project_cooldown_days: Option, + ) -> Self { Self { - cooldown_days: args - .cooldown_days + cooldown_days: cli_cooldown_days + .or(project_cooldown_days) .or_else(|| { filesystem .and_then(|fs| fs.auto_update.as_ref()) - .and_then(|au| au.cooldown_days) + .and_then(|options| options.cooldown_days) }) .unwrap_or_default(), } diff --git a/crates/prek/src/snapshots/prek__config__tests__language_version.snap b/crates/prek/src/snapshots/prek__config__tests__language_version.snap index a1fb461ec..a03475643 100644 --- a/crates/prek/src/snapshots/prek__config__tests__language_version.snap +++ b/crates/prek/src/snapshots/prek__config__tests__language_version.snap @@ -4,6 +4,7 @@ expression: result --- Ok( Config { + auto_update: None, repos: [ Local( LocalRepo { diff --git a/crates/prek/src/snapshots/prek__config__tests__meta_hooks-5.snap b/crates/prek/src/snapshots/prek__config__tests__meta_hooks-5.snap index 8e825914c..afc581817 100644 --- a/crates/prek/src/snapshots/prek__config__tests__meta_hooks-5.snap +++ b/crates/prek/src/snapshots/prek__config__tests__meta_hooks-5.snap @@ -3,6 +3,7 @@ source: crates/prek/src/config.rs expression: result --- Config { + auto_update: None, repos: [ Meta( MetaRepo { diff --git a/crates/prek/src/snapshots/prek__config__tests__numeric_rev_is_parsed_as_string.snap b/crates/prek/src/snapshots/prek__config__tests__numeric_rev_is_parsed_as_string.snap index f5526db74..1ed0992c6 100644 --- a/crates/prek/src/snapshots/prek__config__tests__numeric_rev_is_parsed_as_string.snap +++ b/crates/prek/src/snapshots/prek__config__tests__numeric_rev_is_parsed_as_string.snap @@ -3,6 +3,7 @@ source: crates/prek/src/config.rs expression: config --- Config { + auto_update: None, repos: [ Remote( RemoteRepo { diff --git a/crates/prek/src/snapshots/prek__config__tests__parse_hooks-3.snap b/crates/prek/src/snapshots/prek__config__tests__parse_hooks-3.snap index f5b438ff2..47bbcb92a 100644 --- a/crates/prek/src/snapshots/prek__config__tests__parse_hooks-3.snap +++ b/crates/prek/src/snapshots/prek__config__tests__parse_hooks-3.snap @@ -3,6 +3,7 @@ source: crates/prek/src/config.rs expression: result --- Config { + auto_update: None, repos: [ Local( LocalRepo { diff --git a/crates/prek/src/snapshots/prek__config__tests__parse_repos-3.snap b/crates/prek/src/snapshots/prek__config__tests__parse_repos-3.snap index 12dd498c7..de253da67 100644 --- a/crates/prek/src/snapshots/prek__config__tests__parse_repos-3.snap +++ b/crates/prek/src/snapshots/prek__config__tests__parse_repos-3.snap @@ -3,6 +3,7 @@ source: crates/prek/src/config.rs expression: result --- Config { + auto_update: None, repos: [ Local( LocalRepo { diff --git a/crates/prek/src/snapshots/prek__config__tests__parse_repos-4.snap b/crates/prek/src/snapshots/prek__config__tests__parse_repos-4.snap index a2eabb522..93c42ae52 100644 --- a/crates/prek/src/snapshots/prek__config__tests__parse_repos-4.snap +++ b/crates/prek/src/snapshots/prek__config__tests__parse_repos-4.snap @@ -3,6 +3,7 @@ source: crates/prek/src/config.rs expression: result --- Config { + auto_update: None, repos: [ Remote( RemoteRepo { diff --git a/crates/prek/src/snapshots/prek__config__tests__parse_repos-6.snap b/crates/prek/src/snapshots/prek__config__tests__parse_repos-6.snap index a2eabb522..93c42ae52 100644 --- a/crates/prek/src/snapshots/prek__config__tests__parse_repos-6.snap +++ b/crates/prek/src/snapshots/prek__config__tests__parse_repos-6.snap @@ -3,6 +3,7 @@ source: crates/prek/src/config.rs expression: result --- Config { + auto_update: None, repos: [ Remote( RemoteRepo { diff --git a/crates/prek/src/snapshots/prek__config__tests__parse_repos.snap b/crates/prek/src/snapshots/prek__config__tests__parse_repos.snap index 453a69735..fa4e159cd 100644 --- a/crates/prek/src/snapshots/prek__config__tests__parse_repos.snap +++ b/crates/prek/src/snapshots/prek__config__tests__parse_repos.snap @@ -3,6 +3,7 @@ source: crates/prek/src/config.rs expression: result --- Config { + auto_update: None, repos: [ Local( LocalRepo { diff --git a/crates/prek/src/snapshots/prek__config__tests__read_config_with_merge_keys.snap b/crates/prek/src/snapshots/prek__config__tests__read_config_with_merge_keys.snap index 9a7b52039..1164f40d3 100644 --- a/crates/prek/src/snapshots/prek__config__tests__read_config_with_merge_keys.snap +++ b/crates/prek/src/snapshots/prek__config__tests__read_config_with_merge_keys.snap @@ -3,6 +3,7 @@ source: crates/prek/src/config.rs expression: config --- Config { + auto_update: None, repos: [ Local( LocalRepo { diff --git a/crates/prek/src/snapshots/prek__config__tests__read_config_with_nested_merge_keys.snap b/crates/prek/src/snapshots/prek__config__tests__read_config_with_nested_merge_keys.snap index b3a0d7527..62730b61d 100644 --- a/crates/prek/src/snapshots/prek__config__tests__read_config_with_nested_merge_keys.snap +++ b/crates/prek/src/snapshots/prek__config__tests__read_config_with_nested_merge_keys.snap @@ -3,6 +3,7 @@ source: crates/prek/src/config.rs expression: config --- Config { + auto_update: None, repos: [ Local( LocalRepo { diff --git a/crates/prek/src/snapshots/prek__config__tests__read_toml_config.snap b/crates/prek/src/snapshots/prek__config__tests__read_toml_config.snap index 06ec8ba6d..1c8ae25a3 100644 --- a/crates/prek/src/snapshots/prek__config__tests__read_toml_config.snap +++ b/crates/prek/src/snapshots/prek__config__tests__read_toml_config.snap @@ -3,6 +3,7 @@ source: crates/prek/src/config.rs expression: config --- Config { + auto_update: None, repos: [ Local( LocalRepo { diff --git a/crates/prek/src/snapshots/prek__config__tests__read_yaml_config.snap b/crates/prek/src/snapshots/prek__config__tests__read_yaml_config.snap index 17d8d4a74..736d7ca06 100644 --- a/crates/prek/src/snapshots/prek__config__tests__read_yaml_config.snap +++ b/crates/prek/src/snapshots/prek__config__tests__read_yaml_config.snap @@ -3,6 +3,7 @@ source: crates/prek/src/config.rs expression: config --- Config { + auto_update: None, repos: [ Remote( RemoteRepo { diff --git a/crates/prek/tests/auto_update.rs b/crates/prek/tests/auto_update.rs index f1f514e36..1714b14f7 100644 --- a/crates/prek/tests/auto_update.rs +++ b/crates/prek/tests/auto_update.rs @@ -1902,6 +1902,111 @@ fn auto_update_workspace() -> Result<()> { Ok(()) } +#[test] +fn auto_update_workspace_same_repo_uses_project_cooldown() -> Result<()> { + let context = TestContext::new(); + context.init_project(); + context.write_user_config(indoc::indoc! {r" + [auto_update] + cooldown_days = 1 + "}); + + let repo_path = + create_local_git_repo(&context, "workspace-cooldown-repo", &["v1.0.0", "v1.1.0"])?; + git_cmd(&repo_path) + .arg("commit") + .arg("-m") + .arg("Release v2.0.0") + .arg("--allow-empty") + .assert() + .success(); + git_cmd(&repo_path) + .arg("tag") + .arg("v2.0.0") + .arg("-m") + .arg("v2.0.0") + .assert() + .success(); + + context.setup_workspace( + &["project-a", "project-b"], + "repos: []", // Minimal valid config for root + )?; + + context + .work_dir() + .child("project-a/.pre-commit-config.yaml") + .write_str(&indoc::formatdoc! {r" + auto_update: + cooldown_days: 0 + repos: + - repo: {} + rev: v1.0.0 + hooks: + - id: test-hook + ", repo_path})?; + + context + .work_dir() + .child("project-b/.pre-commit-config.yaml") + .write_str(&indoc::formatdoc! {r" + repos: + - repo: {} + rev: v1.0.0 + hooks: + - id: test-hook + ", repo_path})?; + + context.git_add("."); + + let filters = context.filters(); + + cmd_snapshot!(filters.clone(), context.auto_update(), @" + success: true + exit_code: 0 + ----- stdout ----- + project-a/.pre-commit-config.yaml + [HOME]/test-repos/workspace-cooldown-repo + updating rev `v1.0.0` -> `v2.0.0` + + project-b/.pre-commit-config.yaml + [HOME]/test-repos/workspace-cooldown-repo + updating rev `v1.0.0` -> `v1.1.0` + + ----- stderr ----- + "); + + insta::with_settings!( + { filters => filters.clone() }, + { + assert_snapshot!(context.read("project-a/.pre-commit-config.yaml"), @" + auto_update: + cooldown_days: 0 + repos: + - repo: [HOME]/test-repos/workspace-cooldown-repo + rev: v2.0.0 + hooks: + - id: test-hook + "); + } + ); + + insta::with_settings!( + { filters => filters.clone() }, + { + assert_snapshot!(context.read("project-b/.pre-commit-config.yaml"), @" + repos: + - repo: [HOME]/test-repos/workspace-cooldown-repo + rev: v1.1.0 + hooks: + - id: test-hook + "); + } + ); + + Ok(()) +} + // When multiple tags point to the same object, prek prefers a tag that: // - contains a dot (e.g., a SemVer-like tag), and // - is most similar to the current revision, as measured by Levenshtein distance. diff --git a/crates/prek/tests/global_config.rs b/crates/prek/tests/global_config.rs index 7c5ff328f..4b8d5198c 100644 --- a/crates/prek/tests/global_config.rs +++ b/crates/prek/tests/global_config.rs @@ -3,105 +3,15 @@ use crate::common::{TestContext, cmd_snapshot}; mod common; #[test] -fn global_config_missing_file_uses_defaults() { +fn global_config_missing_file_is_optional() { let context = TestContext::new(); + context.init_project(); + context.write_pre_commit_config("repos: []"); - cmd_snapshot!(context.filters(), context.auto_update().arg("--show-settings"), @" + cmd_snapshot!(context.filters(), context.auto_update(), @" success: true exit_code: 0 ----- stdout ----- - GlobalArgs { - config: None, - cd: None, - color: Auto, - refresh: false, - help: (), - no_progress: false, - quiet: 0, - verbose: 0, - log_file: None, - no_log_file: false, - version: (), - show_settings: true, - } - AutoUpdateSettings { - cooldown_days: 0, - } - - ----- stderr ----- - "); -} - -#[test] -fn global_config_applies_cooldown_days() { - let context = TestContext::new(); - context.write_user_config(indoc::indoc! {r" - [auto_update] - cooldown_days = 3 - "}); - - cmd_snapshot!(context.filters(), context.auto_update().arg("--show-settings"), @" - success: true - exit_code: 0 - ----- stdout ----- - GlobalArgs { - config: None, - cd: None, - color: Auto, - refresh: false, - help: (), - no_progress: false, - quiet: 0, - verbose: 0, - log_file: None, - no_log_file: false, - version: (), - show_settings: true, - } - AutoUpdateSettings { - cooldown_days: 3, - } - - ----- stderr ----- - "); -} - -#[test] -fn global_config_cli_args_override_file() { - let context = TestContext::new(); - context.write_user_config(indoc::indoc! {r" - [auto_update] - cooldown_days = 3 - "}); - - cmd_snapshot!( - context.filters(), - context - .auto_update() - .arg("--show-settings") - .arg("--cooldown-days") - .arg("0"), - @" - success: true - exit_code: 0 - ----- stdout ----- - GlobalArgs { - config: None, - cd: None, - color: Auto, - refresh: false, - help: (), - no_progress: false, - quiet: 0, - verbose: 0, - log_file: None, - no_log_file: false, - version: (), - show_settings: true, - } - AutoUpdateSettings { - cooldown_days: 0, - } ----- stderr ----- "); @@ -110,6 +20,8 @@ fn global_config_cli_args_override_file() { #[test] fn global_config_ignores_unknown_options() { let context = TestContext::new(); + context.init_project(); + context.write_pre_commit_config("repos: []"); context.write_user_config(indoc::indoc! {r#" future_option = true @@ -118,27 +30,10 @@ fn global_config_ignores_unknown_options() { future_option = "ignored" "#}); - cmd_snapshot!(context.filters(), context.auto_update().arg("--show-settings"), @" + cmd_snapshot!(context.filters(), context.auto_update(), @" success: true exit_code: 0 ----- stdout ----- - GlobalArgs { - config: None, - cd: None, - color: Auto, - refresh: false, - help: (), - no_progress: false, - quiet: 0, - verbose: 0, - log_file: None, - no_log_file: false, - version: (), - show_settings: true, - } - AutoUpdateSettings { - cooldown_days: 3, - } ----- stderr ----- "); @@ -147,29 +42,17 @@ fn global_config_ignores_unknown_options() { #[test] fn global_config_invalid_file_reports_parse_error() { let context = TestContext::new(); + context.init_project(); + context.write_pre_commit_config("repos: []"); context.write_user_config(indoc::indoc! {r#" [auto_update] cooldown_days = "soon" "#}); - cmd_snapshot!(context.filters(), context.auto_update().arg("--show-settings"), @r#" + cmd_snapshot!(context.filters(), context.auto_update(), @r#" success: false exit_code: 2 ----- stdout ----- - GlobalArgs { - config: None, - cd: None, - color: Auto, - refresh: false, - help: (), - no_progress: false, - quiet: 0, - verbose: 0, - log_file: None, - no_log_file: false, - version: (), - show_settings: true, - } ----- stderr ----- error: Failed to parse global config `[HOME]/config/prek/prek.toml` diff --git a/docs/configuration.md b/docs/configuration.md index 2542df5c9..93a334022 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -40,7 +40,26 @@ The first supported global setting is the default cooldown for `prek auto-update cooldown_days = 7 ``` -`prek auto-update --cooldown-days ` overrides this value for a single command invocation. +Project config can also define the same setting, scoped to that project: + +=== "prek.toml" + + ```toml + [auto_update] + cooldown_days = 7 + ``` + +=== ".pre-commit-config.yaml" + + ```yaml + auto_update: + cooldown_days: 7 + ``` + +`prek auto-update --cooldown-days ` overrides both project and global config for a single command invocation. +The cooldown value must be between `0` and `255` days, inclusive; `0` disables the cooldown check. + +In workspace mode, project-level `auto_update` settings are not inherited by nested projects. The setting only affects the project config file that defines it; sub-projects use their own `auto_update` setting, then the user-level global config, then the default. ## Pre-commit compatibility @@ -58,6 +77,7 @@ These entries are implemented by `prek` and are not part of the documented upstr They work in both YAML and TOML, but they only matter for compatibility if you share a YAML config with upstream `pre-commit`. - Top-level: + - [`auto_update.cooldown_days`](reference/configuration.md#auto_updatecooldown_days) - [`minimum_prek_version`](reference/configuration.md#prek-only-minimum-prek-version-config) - [`orphan`](reference/configuration.md#prek-only-orphan) - Repo type: diff --git a/docs/reference/cli.md b/docs/reference/cli.md index 06e1fe3cb..c7067e19f 100644 --- a/docs/reference/cli.md +++ b/docs/reference/cli.md @@ -561,7 +561,7 @@ prek auto-update [OPTIONS]
  • never: Disables colored output
  • --config, -c config

    Path to alternate config file

    --cooldown-days days

    Minimum release age (in days) required for a version to be eligible.

    -

    The age is computed from the tag creation timestamp for annotated tags, or from the tagged commit timestamp for lightweight tags. Defaults to auto_update.cooldown_days in the global config, or 0 when unset. A value of 0 disables this check.

    +

    The age is computed from the tag creation timestamp for annotated tags, or from the tagged commit timestamp for lightweight tags. Defaults to auto_update.cooldown_days in the project or global config, or 0 when unset. Valid values are 0 through 255; 0 disables this check.

    --dry-run

    Do not write changes to the config file, only display what would be changed

    --exclude-repo repo

    Do not update this repository. This option may be specified multiple times

    --exclude-tag pattern

    Ignore tags matching this glob pattern. This option may be specified multiple times.

    diff --git a/docs/reference/configuration.md b/docs/reference/configuration.md index 0a1846dac..a7b820222 100644 --- a/docs/reference/configuration.md +++ b/docs/reference/configuration.md @@ -11,11 +11,11 @@ This page documents the configuration keys that `prek` understands. This file stores user-level `prek` settings and does not define project hooks. -### `auto_update.cooldown_days` +### Global `auto_update.cooldown_days` Default cooldown for `prek auto-update`. -- Type: integer days +- Type: integer days, `0` to `255` - Default: `0` - CLI override: `prek auto-update --cooldown-days ` @@ -26,8 +26,39 @@ cooldown_days = 7 The age is computed from the tag creation timestamp for annotated tags, or from the tagged commit timestamp for lightweight tags. A value of `0` disables the cooldown check. +Project configs can also set `auto_update.cooldown_days`. The effective precedence is: + +1. `prek auto-update --cooldown-days ` +2. project config +3. user-level global config +4. default `0` + ## Top-level keys +### `auto_update.cooldown_days` + +Project default cooldown for `prek auto-update`. + +- Type: integer days, `0` to `255` +- Default: inherited from the user-level global config, or `0` +- CLI override: `prek auto-update --cooldown-days ` + +=== "prek.toml" + + ```toml + [auto_update] + cooldown_days = 7 + ``` + +=== ".pre-commit-config.yaml" + + ```yaml + auto_update: + cooldown_days: 7 + ``` + +In workspace mode, this setting is scoped to the project config file that defines it. It applies only to that project and is not inherited by nested projects. Sub-projects use their own `auto_update` setting, then the user-level global config, then the default. If two projects use the same repo URL with different cooldown settings, `prek auto-update` fetches the repo once but evaluates each project with its own cooldown. + ### `repos` (required) A list of hook repositories. diff --git a/prek.schema.json b/prek.schema.json index 682244747..cd545a84a 100644 --- a/prek.schema.json +++ b/prek.schema.json @@ -5,6 +5,10 @@ "description": "The configuration file for prek, a git hook manager written in Rust.", "type": "object", "properties": { + "auto_update": { + "description": "Default settings for `prek auto-update` in this project.", + "$ref": "#/definitions/AutoUpdateOptions" + }, "repos": { "type": "array", "items": { @@ -129,6 +133,17 @@ "additionalProperties": true, "x-tombi-toml-version": "v1.1.0", "definitions": { + "AutoUpdateOptions": { + "description": "Controls how `prek auto-update` selects eligible releases.", + "type": "object", + "properties": { + "cooldown_days": { + "type": "integer", + "maximum": 255, + "minimum": 0 + } + } + }, "Repo": { "description": "A repository of hooks, which can be remote, local, meta, or builtin.", "type": "object", From 56d6d0c13ef36a4ab6a705621fba41448f2b503d Mon Sep 17 00:00:00 2001 From: Jo <10510431+j178@users.noreply.github.com> Date: Tue, 5 May 2026 13:43:41 +0800 Subject: [PATCH 23/23] Bump version to 0.3.12 (#2045) --- .github/workflows/build-release-binaries.yml | 4 -- CHANGELOG.md | 40 ++++++++++++++++++++ Cargo.lock | 8 ++-- Cargo.toml | 8 ++-- README.md | 4 +- docs/integrations.md | 6 +-- mise.toml | 3 +- pyproject.toml | 2 +- uv.lock | 2 +- 9 files changed, 57 insertions(+), 20 deletions(-) diff --git a/.github/workflows/build-release-binaries.yml b/.github/workflows/build-release-binaries.yml index 7e31276f8..bf6558de9 100644 --- a/.github/workflows/build-release-binaries.yml +++ b/.github/workflows/build-release-binaries.yml @@ -17,10 +17,6 @@ on: permissions: {} -concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true - env: CARGO_INCREMENTAL: 0 CARGO_NET_RETRY: 10 diff --git a/CHANGELOG.md b/CHANGELOG.md index 8909b8915..f808a4ba3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,45 @@ # Changelog +## 0.3.12 + +Released on 2026-05-05. + +### Highlights + +`auto_update.cooldown_days` is now available in both the user-level global +config (`~/.config/prek/prek.toml` on Linux and macOS, or +`$XDG_CONFIG_HOME/prek/prek.toml` when set; `%APPDATA%\prek\prek.toml` on +Windows) and project config. Set a user default for `prek auto-update`, then +override it per project when a repository needs a different update cadence. + +```toml +[auto_update] +cooldown_days = 7 +``` + +### Enhancements + +- Add global auto-update cooldown config ([#2041](https://github.com/j178/prek/pull/2041)) +- Add project auto-update cooldown config ([#2044](https://github.com/j178/prek/pull/2044)) +- Support `language: dart` ([#1146](https://github.com/j178/prek/pull/1146)) + +### Bug fixes + +- Pass commit message file to workspace hooks ([#2043](https://github.com/j178/prek/pull/2043)) +- Preserve non-UTF8 filenames from git ([#2023](https://github.com/j178/prek/pull/2023)) +- ruby: put resolved Ruby's bin dir on `$PATH` for `gem` invocations ([#2021](https://github.com/j178/prek/pull/2021)) + +### Documentation + +- Update docs with the new logo and icon ([#2025](https://github.com/j178/prek/pull/2025)) +- Point schema docs to SchemaStore ([#2039](https://github.com/j178/prek/pull/2039)) + +### Contributors + +- @j178 +- @xiaoyanli-lyft +- @Lutra-Fs + ## 0.3.11 Released on 2026-04-27. diff --git a/Cargo.lock b/Cargo.lock index 309d47bab..db476d7b7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2109,7 +2109,7 @@ dependencies = [ [[package]] name = "prek" -version = "0.3.11" +version = "0.3.12" dependencies = [ "aho-corasick", "annotate-snippets", @@ -2192,14 +2192,14 @@ dependencies = [ [[package]] name = "prek-consts" -version = "0.3.11" +version = "0.3.12" dependencies = [ "tracing", ] [[package]] name = "prek-identify" -version = "0.3.11" +version = "0.3.12" dependencies = [ "anyhow", "fs-err", @@ -2215,7 +2215,7 @@ dependencies = [ [[package]] name = "prek-pty" -version = "0.3.11" +version = "0.3.12" dependencies = [ "rustix", "tokio", diff --git a/Cargo.toml b/Cargo.toml index 17cbb8fd3..045bc3e6f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,7 +3,7 @@ members = ["crates/*"] resolver = "3" [workspace.package] -version = "0.3.11" +version = "0.3.12" edition = "2024" rust-version = "1.93.0" repository = "https://github.com/j178/prek" @@ -11,9 +11,9 @@ homepage = "https://prek.j178.dev/" license = "MIT" [workspace.dependencies] -prek-consts = { path = "crates/prek-consts", version = "0.3.11" } -prek-identify = { path = "crates/prek-identify", version = "0.3.11" } -prek-pty = { path = "crates/prek-pty", version = "0.3.11" } +prek-consts = { path = "crates/prek-consts", version = "0.3.12" } +prek-identify = { path = "crates/prek-identify", version = "0.3.12" } +prek-pty = { path = "crates/prek-pty", version = "0.3.12" } aho-corasick = { version = "1.1.4" } annotate-snippets = { version = "0.12.13" } diff --git a/README.md b/README.md index d43a733b3..f22bc4cc7 100644 --- a/README.md +++ b/README.md @@ -60,7 +60,7 @@ On Linux and macOS: ```bash -curl --proto '=https' --tlsv1.2 -LsSf https://github.com/j178/prek/releases/download/v0.3.11/prek-installer.sh | sh +curl --proto '=https' --tlsv1.2 -LsSf https://github.com/j178/prek/releases/download/v0.3.12/prek-installer.sh | sh ``` @@ -70,7 +70,7 @@ On Windows: ```powershell -powershell -ExecutionPolicy ByPass -c "irm https://github.com/j178/prek/releases/download/v0.3.11/prek-installer.ps1 | iex" +powershell -ExecutionPolicy ByPass -c "irm https://github.com/j178/prek/releases/download/v0.3.12/prek-installer.ps1 | iex" ``` diff --git a/docs/integrations.md b/docs/integrations.md index 5e8bb6a3d..6caef11ba 100644 --- a/docs/integrations.md +++ b/docs/integrations.md @@ -14,13 +14,13 @@ A common pattern is to copy the binary into your own image: ```dockerfile FROM debian:bookworm-slim -COPY --from=ghcr.io/j178/prek:v0.3.11 /prek /usr/local/bin/prek +COPY --from=ghcr.io/j178/prek:v0.3.12 /prek /usr/local/bin/prek ``` If you prefer, you can also run the distroless image directly: ```bash -docker run --rm ghcr.io/j178/prek:v0.3.11 --version +docker run --rm ghcr.io/j178/prek:v0.3.12 --version ``` ### Verifying Images @@ -43,7 +43,7 @@ Loaded 1 attestation from GitHub API !!! tip - Use a specific version tag (e.g., `ghcr.io/j178/prek:v0.3.11`) or image + Use a specific version tag (e.g., `ghcr.io/j178/prek:v0.3.12`) or image digest rather than `latest` for verification. ## GitHub Actions diff --git a/mise.toml b/mise.toml index 9f0fb2aa3..a9a56de8c 100644 --- a/mise.toml +++ b/mise.toml @@ -71,5 +71,6 @@ description = "Prepare for a release" run = """ git checkout -b bump uv run --group dev rooster release -prek run mdformat --files CHANGELOG.md +prek run mdformat --files CHANGELOG.md || true +uv lock """ diff --git a/pyproject.toml b/pyproject.toml index ca81dcd99..fa60b35bf 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "maturin" [project] name = "prek" -version = "0.3.11" +version = "0.3.12" description = "A fast Git hook manager written in Rust, designed as a drop-in alternative to pre-commit, reimagined." authors = [{ name = "j178", email = "hi@j178.dev" }] requires-python = ">=3.8" diff --git a/uv.lock b/uv.lock index c13f73ec5..67fb9c069 100644 --- a/uv.lock +++ b/uv.lock @@ -433,7 +433,7 @@ wheels = [ [[package]] name = "prek" -version = "0.3.11" +version = "0.3.12" source = { virtual = "." } [package.dev-dependencies]