Warn on shallow history
ober
db731d12bf838eff3cec0efd992190df3d3c61be
--- a/README.md +++ b/README.md @@ -62,8 +62,9 @@ analyzed per commit, and 50,000 bytes per AI note. When a limit is hit, output keeps the bounded data and includes a warning. Warnings also call out root commits with no parent baseline, merge commits where -the scanner intentionally uses the first-parent diff, and binary file changes -that are skipped by text-line heuristics. +the scanner intentionally uses the first-parent diff, missing parent objects in +shallow history, and binary file changes that are skipped by text-line +heuristics. ## What It Reads --- a/main-binary.ss +++ b/main-binary.ss @@ -142,10 +142,22 @@ (try (run-process (append (list "git" "-C" repo "--literal-pathspecs") args)) (catch (e) ""))) +(def (git-ok? repo args) + (try + (begin + (run-process (append (list "git" "-C" repo "--literal-pathspecs") args)) + #t) + (catch (e) #f))) + +(def (commit-available? repo rev) + (or (string-empty? rev) + (git-ok? repo (list "cat-file" "-e" (str rev "^{commit}"))))) (def (repo-root path) (let ([root (string-trim (git path '("rev-parse" "--show-toplevel")))]) (if (string-empty? root) #f root))) +(def (shallow-repository? repo) + (same-public-string? (string-trim (git repo '("rev-parse" "--is-shallow-repository"))) "true")) (def (commit-list repo count commit from to file) (if commit @@ -525,14 +537,18 @@ (def (commit-shape-warnings parents) (append (if (root-commit? parents) '("root commit; no parent diff baseline") '()) (if (merge-commit? parents) '("merge commit; scanner uses first-parent diff") '()))) +(def (parent-history-warnings shallow? missing-parent?) + (append (if shallow? '("repository is shallow; parent history may be unavailable") '()) + (if missing-parent? '("parent object unavailable; history may be shallow") '()))) (def (binary-change-warnings binary-count) (if (> binary-count 0) (list (str "binary file changes skipped: " binary-count)) '())) -(def (warnings files lines note note-obj metadata-only? heuristics-only? min-lines file-count line-count note-count parents binary-count) +(def (warnings files lines note note-obj metadata-only? heuristics-only? min-lines file-count line-count note-count parents shallow? binary-count missing-parent?) (append (commit-shape-warnings parents) + (parent-history-warnings shallow? missing-parent?) (binary-change-warnings binary-count) (if (null? files) '("no changed text files found or commit is unavailable") '()) (if (null? lines) '("no added UTF-8 patch lines available") '()) @@ -549,6 +565,8 @@ (def (scan-one repo rev hashes revs file min-lines metadata-only? heuristics-only?) (let* ([fields (commit-fields repo rev)] [id (safe-ref fields 0 rev)] [parents (safe-ref fields 1 "")] [parent (first-parent parents)] + [shallow? (shallow-repository? repo)] + [missing-parent? (and (not (string-empty? parent)) (not (commit-available? repo parent)))] [author-name (safe-ref fields 2 "")] [author-email (safe-ref fields 3 "")] [time (parse-int (safe-ref fields 4 "0") 0)] [subject (safe-ref fields 5 "")] [body (commit-message repo rev)] [file-count (changed-file-count repo rev file)] @@ -574,7 +592,7 @@ [heuristics-only? (verdict score '() "")] [else (verdict score metadata note)])]) (list (make-finding id parent author-name author-email time subject paths adds dels (length lines) note attribution metadata signals score v - (warnings files lines note note-obj metadata-only? heuristics-only? min-lines file-count line-count note-count parents binary-count)) + (warnings files lines note note-obj metadata-only? heuristics-only? min-lines file-count line-count note-count parents shallow? binary-count missing-parent?)) (cadr sim-pair)))) (def (scan-repo repo revs file min-lines metadata-only? heuristics-only?) --- a/tests/fixture-smoke.sh +++ b/tests/fixture-smoke.sh @@ -3,7 +3,8 @@ set -eu root=$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd) fixture=$(mktemp -d) -trap 'rm -rf "$fixture"' EXIT +shallow=$(mktemp -d) +trap 'rm -rf "$fixture" "$shallow"' EXIT git -C "$fixture" init -q git -C "$fixture" config user.name "Human Dev" @@ -203,6 +204,11 @@ binary_json=$("$root/bin/jerboa-aigit" scan "$fixture" --format json --commit "$ printf '%s\n' "$binary_json" | grep -q 'binary file changes skipped: 1' printf '%s\n' "$binary_json" | grep -q 'no added UTF-8 patch lines available' +shallow_repo="$shallow/repo" +git clone -q --depth 1 "file://$fixture" "$shallow_repo" +shallow_json=$("$root/bin/jerboa-aigit" scan "$shallow_repo" --format json --count 1) +printf '%s\n' "$shallow_json" | grep -q 'repository is shallow; parent history may be unavailable' + if "$root/bin/jerboa-aigit" scan "$fixture/nope" >/tmp/jerboa-aigit-invalid.out 2>&1; then echo "invalid repository path should fail" >&2 exit 1