Installs pre-commit hooks for OCaml projects that run dune fmt automatically

precommit: scan for git projects recursively by default

Remove the -r/--recursive flag. All commands now recursively scan
the given root directories (default .) for git projects automatically.

+33 -35
+33 -35
bin/main.ml
··· 20 20 (* {1 Common arguments} *) 21 21 22 22 let dirs = 23 - let doc = "Directories to operate on. Defaults to the current directory." in 23 + let doc = 24 + "Root directories to scan for git projects. Defaults to the current \ 25 + directory. Each directory is scanned recursively for repositories \ 26 + containing a $(b,.git) entry." 27 + in 24 28 Arg.(value & pos_all dir [ "." ] & info [] ~docv:"DIR" ~doc) 25 29 26 30 let dry_run = 27 31 let doc = "Show what would be done without making changes." in 28 32 Arg.(value & flag & info [ "n"; "dry-run" ] ~doc) 29 - 30 - let recursive = 31 - let doc = "Operate on all OCaml projects in subdirectories." in 32 - Arg.(value & flag & info [ "r"; "recursive" ] ~doc) 33 33 34 34 let force = 35 35 let doc = "Install hooks even if no dune-project is found." in ··· 71 71 error "%s" msg; 72 72 exit 1 73 73 74 - let collect_dirs ~fs ~recursive dirs = 75 - if recursive then 76 - List.concat_map (fun d -> Precommit.find_git_projects ~fs d) dirs 77 - else dirs 74 + let collect_dirs ~fs dirs = 75 + List.concat_map (fun d -> Precommit.find_git_projects ~fs d) dirs 78 76 79 77 (* {1 Init command} *) 80 78 81 - let init_impl ~fs dry_run force hooks recursive dirs = 82 - let dirs = collect_dirs ~fs ~recursive dirs in 79 + let init_impl ~fs dry_run force hooks dirs = 80 + let dirs = collect_dirs ~fs dirs in 83 81 let count = ref 0 in 84 82 List.iter 85 83 (fun d -> ··· 99 97 Log.info (fun m -> 100 98 m "Processed %d director%s" !count (if !count = 1 then "y" else "ies")) 101 99 102 - let init dry_run force hooks recursive dirs = 100 + let init dry_run force hooks dirs = 103 101 Eio_main.run @@ fun env -> 104 102 let fs = Eio.Stdenv.cwd env in 105 - init_impl ~fs dry_run force hooks recursive dirs 103 + init_impl ~fs dry_run force hooks dirs 106 104 107 105 let init_cmd = 108 106 let doc = "Initialise pre-commit hooks for OCaml projects." in ··· 117 115 `P "Initialise hooks in the current directory:"; 118 116 `Pre " precommit init"; 119 117 `P "Initialise hooks in all projects under src/:"; 120 - `Pre " precommit init -r src/"; 118 + `Pre " precommit init src/"; 121 119 `P "Preview what would be done:"; 122 - `Pre " precommit init -n -r ."; 120 + `Pre " precommit init -n"; 123 121 `P "Install only the AI attribution hook in a non-OCaml project:"; 124 122 `Pre " precommit init -f --hooks ai"; 125 123 `P "Install only the dune fmt hook:"; ··· 127 125 ] 128 126 in 129 127 let info = Cmd.info "init" ~doc ~man in 130 - Cmd.v info Term.(const init $ dry_run $ force $ hooks $ recursive $ dirs) 128 + Cmd.v info Term.(const init $ dry_run $ force $ hooks $ dirs) 131 129 132 130 (* {1 Status command} *) 133 131 ··· 135 133 if b then Tty.Span.styled Tty.Style.(fg Tty.Color.green) "+" 136 134 else Tty.Span.styled Tty.Style.(fg Tty.Color.red) "-" 137 135 138 - let status_impl ~fs recursive dirs = 139 - let dirs = collect_dirs ~fs ~recursive dirs in 136 + let status_impl ~fs dirs = 137 + let dirs = collect_dirs ~fs dirs in 140 138 let missing = ref 0 in 141 139 let ok = ref 0 in 142 140 let rows = ··· 183 181 else if !ok > 0 then 184 182 success "%d project%s properly configured" !ok (if !ok = 1 then "" else "s") 185 183 186 - let status recursive dirs = 184 + let status dirs = 187 185 Eio_main.run @@ fun env -> 188 186 let fs = Eio.Stdenv.cwd env in 189 - status_impl ~fs recursive dirs 187 + status_impl ~fs dirs 190 188 191 189 let status_cmd = 192 190 let doc = "Check pre-commit hook status." in ··· 200 198 hooks, .ocamlformat, or has formatting disabled."; 201 199 `S Manpage.s_examples; 202 200 `P "Check status of all projects under src/:"; 203 - `Pre " precommit status -r src/"; 201 + `Pre " precommit status src/"; 204 202 ] 205 203 in 206 204 let info = Cmd.info "status" ~doc ~man in 207 - Cmd.v info Term.(const status $ recursive $ dirs) 205 + Cmd.v info Term.(const status $ dirs) 208 206 209 207 (* {1 Check command} *) 210 208 ··· 273 271 end; 274 272 (List.rev !affected_dirs, !total_commits, !repos_with_issues) 275 273 276 - let check_impl ~process_mgr ~fs recursive dirs = 277 - let dirs = collect_dirs ~fs ~recursive dirs in 274 + let check_impl ~process_mgr ~fs dirs = 275 + let dirs = collect_dirs ~fs dirs in 278 276 let _affected, total_commits, repos_with_issues = 279 277 find_and_display_ai_commits ~process_mgr ~fs dirs 280 278 in ··· 287 285 end 288 286 else success "No AI attribution found in commit history" 289 287 290 - let check recursive dirs = 288 + let check dirs = 291 289 Eio_main.run @@ fun env -> 292 290 let fs = Eio.Stdenv.cwd env in 293 291 let process_mgr = Eio.Stdenv.process_mgr env in 294 - check_impl ~process_mgr ~fs recursive dirs 292 + check_impl ~process_mgr ~fs dirs 295 293 296 294 let check_cmd = 297 295 let doc = "Check git history for commits with AI attribution." in ··· 303 301 'claude' in the commit message. Exit code is 1 if any are found."; 304 302 `S Manpage.s_examples; 305 303 `P "Check all projects under src/:"; 306 - `Pre " precommit check -r src/"; 304 + `Pre " precommit check src/"; 307 305 ] 308 306 in 309 307 let info = Cmd.info "check" ~doc ~man in 310 - Cmd.v info Term.(const check $ recursive $ dirs) 308 + Cmd.v info Term.(const check $ dirs) 311 309 312 310 (* {1 Fix command} *) 313 311 ··· 334 332 let answer = String.trim line in 335 333 answer = "y" || answer = "Y" 336 334 337 - let fix_impl ~process_mgr ~fs dry_run yes recursive dirs = 338 - let dirs = collect_dirs ~fs ~recursive dirs in 335 + let fix_impl ~process_mgr ~fs dry_run yes dirs = 336 + let dirs = collect_dirs ~fs dirs in 339 337 let affected, total_commits, repos_with_issues = 340 338 find_and_display_ai_commits ~process_mgr ~fs dirs 341 339 in ··· 387 385 let doc = "Skip interactive confirmation prompt." in 388 386 Arg.(value & flag & info [ "y"; "yes" ] ~doc) 389 387 390 - let fix dry_run yes recursive dirs = 388 + let fix dry_run yes dirs = 391 389 Eio_main.run @@ fun env -> 392 390 let fs = Eio.Stdenv.cwd env in 393 391 let process_mgr = Eio.Stdenv.process_mgr env in 394 - fix_impl ~process_mgr ~fs dry_run yes recursive dirs 392 + fix_impl ~process_mgr ~fs dry_run yes dirs 395 393 396 394 let fix_cmd = 397 395 let doc = "Remove AI attribution from commit history." in ··· 408 406 the interactive confirmation prompt."; 409 407 `S Manpage.s_examples; 410 408 `P "Fix all projects under the current directory:"; 411 - `Pre " precommit fix -r"; 409 + `Pre " precommit fix"; 412 410 `P "Preview what would be done:"; 413 - `Pre " precommit fix -n -r ."; 411 + `Pre " precommit fix -n"; 414 412 `P "Fix without confirmation prompt:"; 415 413 `Pre " precommit fix -y"; 416 414 ] 417 415 in 418 416 let info = Cmd.info "fix" ~doc ~man in 419 - Cmd.v info Term.(const fix $ dry_run $ yes $ recursive $ dirs) 417 + Cmd.v info Term.(const fix $ dry_run $ yes $ dirs) 420 418 421 419 (* {1 Main} *) 422 420