ai-push-hooks 0.1.15 → 0.1.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ai-push-hooks",
3
- "version": "0.1.15",
3
+ "version": "0.1.16",
4
4
  "description": "Modular AI push-hook workflow runner",
5
5
  "license": "MIT",
6
6
  "repository": {
package/pyproject.toml CHANGED
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "ai-push-hooks"
7
- version = "0.1.15"
7
+ version = "0.1.16"
8
8
  description = "Modular AI push-hook workflow runner"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -11,7 +11,13 @@ import subprocess
11
11
  from pathlib import PurePosixPath
12
12
  from typing import Any
13
13
 
14
- from ..types import FEATURE_BRANCH_PREFIXES, HookError, ModuleRuntimeState, RuntimeContext, StepConfig
14
+ from ..types import (
15
+ FEATURE_BRANCH_PREFIXES,
16
+ HookError,
17
+ ModuleRuntimeState,
18
+ RuntimeContext,
19
+ StepConfig,
20
+ )
15
21
 
16
22
  ZERO_OID = "0000000000000000000000000000000000000000"
17
23
 
@@ -145,10 +151,17 @@ def collect_ranges_from_stdin(
145
151
  if local_sha == ZERO_OID:
146
152
  continue
147
153
  if remote_sha and remote_sha != ZERO_OID:
148
- if run_command(["git", "cat-file", "-e", f"{remote_sha}^{{commit}}"], cwd=repo_root).returncode == 0:
154
+ if (
155
+ run_command(
156
+ ["git", "cat-file", "-e", f"{remote_sha}^{{commit}}"], cwd=repo_root
157
+ ).returncode
158
+ == 0
159
+ ):
149
160
  ranges.add(f"{remote_sha}..{local_sha}")
150
161
  else:
151
- merge_base = git(repo_root, ["merge-base", local_sha, f"{remote_name}/main"], check=False)
162
+ merge_base = git(
163
+ repo_root, ["merge-base", local_sha, f"{remote_name}/main"], check=False
164
+ )
152
165
  if merge_base:
153
166
  ranges.add(f"{merge_base}..{local_sha}")
154
167
  else:
@@ -156,7 +169,9 @@ def collect_ranges_from_stdin(
156
169
  if ranges:
157
170
  return sorted(ranges)
158
171
 
159
- upstream = git(repo_root, ["rev-parse", "--abbrev-ref", "--symbolic-full-name", "@{upstream}"], check=False)
172
+ upstream = git(
173
+ repo_root, ["rev-parse", "--abbrev-ref", "--symbolic-full-name", "@{upstream}"], check=False
174
+ )
160
175
  if upstream:
161
176
  merge_base = git(repo_root, ["merge-base", "HEAD", upstream], check=False)
162
177
  if merge_base:
@@ -170,7 +185,9 @@ def collect_ranges_from_stdin(
170
185
  def collect_changed_files(repo_root: pathlib.Path, ranges: list[str]) -> list[str]:
171
186
  files: set[str] = set()
172
187
  for range_expr in ranges:
173
- output = git(repo_root, ["diff", "--name-only", "--diff-filter=ACMR", range_expr], check=True)
188
+ output = git(
189
+ repo_root, ["diff", "--name-only", "--diff-filter=ACMR", range_expr], check=True
190
+ )
174
191
  for line in output.splitlines():
175
192
  clean = line.strip()
176
193
  if clean:
@@ -186,18 +203,29 @@ def collect_diff(repo_root: pathlib.Path, ranges: list[str], max_bytes: int) ->
186
203
  return "\n".join(chunks)[:max_bytes]
187
204
 
188
205
 
189
- def collect_commit_messages_for_ranges(repo_root: pathlib.Path, ranges: list[str]) -> list[dict[str, str]]:
206
+ def collect_commit_messages_for_ranges(
207
+ repo_root: pathlib.Path, ranges: list[str]
208
+ ) -> list[dict[str, str]]:
190
209
  commits: list[dict[str, str]] = []
191
210
  for range_expr in ranges:
192
- raw = git(repo_root, ["log", "--format=%H%x1f%s%x1f%b%x1e", range_expr], check=True)
211
+ completed = run_command(
212
+ ["git", "log", "--format=%H%x1f%s%x1f%b%x1e", range_expr],
213
+ cwd=repo_root,
214
+ check=True,
215
+ )
216
+ raw = completed.stdout or ""
193
217
  for record in raw.split("\x1e"):
194
- payload = record.strip()
218
+ payload = record.rstrip("\r\n")
195
219
  if not payload:
196
220
  continue
197
221
  parts = payload.split("\x1f", 2)
198
- if len(parts) != 3:
222
+ if len(parts) == 2:
223
+ commit_hash, subject = parts
224
+ body = ""
225
+ elif len(parts) == 3:
226
+ commit_hash, subject, body = parts
227
+ else:
199
228
  continue
200
- commit_hash, subject, body = parts
201
229
  commits.append(
202
230
  {
203
231
  "hash": commit_hash.strip(),
@@ -229,7 +257,19 @@ def parse_key_value_text(text: str) -> dict[str, str]:
229
257
 
230
258
  def lookup_open_pr_url(repo_root: pathlib.Path, branch_name: str) -> str:
231
259
  completed = run_command(
232
- ["gh", "pr", "list", "--head", branch_name, "--state", "open", "--limit", "1", "--json", "url"],
260
+ [
261
+ "gh",
262
+ "pr",
263
+ "list",
264
+ "--head",
265
+ branch_name,
266
+ "--state",
267
+ "open",
268
+ "--limit",
269
+ "1",
270
+ "--json",
271
+ "url",
272
+ ],
233
273
  cwd=repo_root,
234
274
  check=False,
235
275
  )
@@ -292,10 +332,24 @@ def attempt_pr_creation_fallback(
292
332
  changed_files: list[str],
293
333
  commits: list[dict[str, str]],
294
334
  ) -> str:
295
- title = sanitize_pr_title(git(repo_root, ["log", "-1", "--pretty=%s"], check=False), branch_name)
335
+ title = sanitize_pr_title(
336
+ git(repo_root, ["log", "-1", "--pretty=%s"], check=False), branch_name
337
+ )
296
338
  body = build_fallback_pr_body(branch_name, ranges, changed_files, commits)
297
339
  created = run_command(
298
- ["gh", "pr", "create", "--head", branch_name, "--base", base_branch, "--title", title, "--body", body],
340
+ [
341
+ "gh",
342
+ "pr",
343
+ "create",
344
+ "--head",
345
+ branch_name,
346
+ "--base",
347
+ base_branch,
348
+ "--title",
349
+ title,
350
+ "--body",
351
+ body,
352
+ ],
299
353
  cwd=repo_root,
300
354
  check=False,
301
355
  )
@@ -307,11 +361,15 @@ def attempt_pr_creation_fallback(
307
361
  existing_pr = lookup_open_pr_url(repo_root, branch_name)
308
362
  if existing_pr:
309
363
  return existing_pr
310
- raise HookError(combined_output.strip() or f"gh pr create failed with exit code {created.returncode}")
364
+ raise HookError(
365
+ combined_output.strip() or f"gh pr create failed with exit code {created.returncode}"
366
+ )
311
367
 
312
368
 
313
369
  def remote_branch_exists(repo_root: pathlib.Path, remote_name: str, branch_name: str) -> bool:
314
- completed = run_command(["git", "ls-remote", "--heads", remote_name, branch_name], cwd=repo_root, check=False)
370
+ completed = run_command(
371
+ ["git", "ls-remote", "--heads", remote_name, branch_name], cwd=repo_root, check=False
372
+ )
315
373
  return completed.returncode == 0 and bool((completed.stdout or "").strip())
316
374
 
317
375
 
@@ -385,14 +443,28 @@ def gh_pr_create_executor(
385
443
  title = sanitize_pr_title(str(payload.get("title", "")).strip(), branch_name)
386
444
  body = str(payload.get("body", "")).strip()
387
445
  if not body:
388
- commits = collect_commit_messages_for_ranges(context.repo_root, context.cache.get("ranges", []))
446
+ commits = collect_commit_messages_for_ranges(
447
+ context.repo_root, context.cache.get("ranges", [])
448
+ )
389
449
  body = build_fallback_pr_body(
390
450
  branch_name,
391
451
  context.cache.get("ranges", []),
392
452
  context.cache.get("changed_files", []),
393
453
  commits,
394
454
  )
395
- args = ["gh", "pr", "create", "--head", head_branch, "--base", base_branch, "--title", title, "--body", body]
455
+ args = [
456
+ "gh",
457
+ "pr",
458
+ "create",
459
+ "--head",
460
+ head_branch,
461
+ "--base",
462
+ base_branch,
463
+ "--title",
464
+ title,
465
+ "--body",
466
+ body,
467
+ ]
396
468
  if bool(payload.get("draft", False)):
397
469
  args.append("--draft")
398
470
  created = run_command(args, cwd=context.repo_root, check=False)
@@ -402,7 +474,10 @@ def gh_pr_create_executor(
402
474
  pr_url = lookup_open_pr_url(context.repo_root, branch_name)
403
475
  if not pr_url:
404
476
  if remote_branch_exists(context.repo_root, context.remote_name or "origin", branch_name):
405
- raise HookError(combined_output.strip() or f"gh pr create failed with exit code {created.returncode}")
477
+ raise HookError(
478
+ combined_output.strip()
479
+ or f"gh pr create failed with exit code {created.returncode}"
480
+ )
406
481
  return {"skipped": False, "pr_url": "", "deferred_until_remote": True}
407
482
  return {"skipped": False, "pr_url": pr_url, "already_exists": False}
408
483