ThinkThen

Bash techniques
Bash · Recipes

Review a diff by what it does

jq cuts a unified diff into hunks. decide asks of each hunk whether it changes what the code does. The file name and the hunk header stay in each record.

change.diff, a file the script reads
diff --git a/billing.py b/billing.py
--- a/billing.py
+++ b/billing.py
@@ -3,2 +3,2 @@ def late_fee(days):
-    # charge a fee after 30 days
+    # Charge a fee after 30 days.
     if days > 30:
@@ -8,2 +8,2 @@ def refund(amount, limit):
-    if amount > limit:
+    if amount >= limit:
         return False
@@ -14,3 +14,3 @@ def total(items):
-    t = 0
-    for i in items: t += i.price
-    return t
+    subtotal = 0
+    for item in items: subtotal += item.price
+    return subtotal
@@ -20,1 +20,1 @@ def tax(amount):
-    return amount * 0.07
+    return round(amount * 0.07, 2)
hunks.jq, a file the script reads
reduce inputs as $line ({file: null, hunks: []};
  if ($line | startswith("+++ b/")) then
    .file = $line[6:]
  elif ($line | startswith("@@")) then
    .hunks += [{file, at: $line, hunk: ""}]
  elif (.hunks | length) > 0
    and ($line | test("^(diff |--- )") | not) then
    .hunks[-1].hunk += $line + "\n"
  else
    .
  end)
| .hunks[]
Two hunks change what the code does: the refund limit and the rounded tax. The comment and the rename do not.
question="Does this change what the code does when it runs?"

jq -cRnf hunks.jq change.diff |
thinkthen decide "$question" \
  --batch 1 \
  --jsonl \
  --field /hunk |
jq '{file: .input.file, at: .input.at, changes: .value}'
Output
{
  "file": "billing.py",
  "at": "@@ -3,2 +3,2 @@ def late_fee(days):",
  "changes": false
}
{
  "file": "billing.py",
  "at": "@@ -8,2 +8,2 @@ def refund(amount, limit):",
  "changes": true
}
{
  "file": "billing.py",
  "at": "@@ -14,3 +14,3 @@ def total(items):",
  "changes": false
}
{
  "file": "billing.py",
  "at": "@@ -20,1 +20,1 @@ def tax(amount):",
  "changes": true
}
exit 0