Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/analyzers/activity.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ def analyze(
try:
dates.append(datetime.fromisoformat(pub.replace("Z", "+00:00")))
except (ValueError, TypeError):
# Ignore malformed release timestamps when estimating cadence.
pass
if len(dates) >= 2:
dates.sort()
Expand Down
1 change: 1 addition & 0 deletions src/analyzers/cicd.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ def _has_build_scripts(repo_path: Path) -> bool:
if "build" in scripts or "test" in scripts:
return True
except (json.JSONDecodeError, OSError):
# Malformed or unreadable package metadata means no script signal is detected.
pass

# Makefile
Expand Down
6 changes: 6 additions & 0 deletions src/analyzers/dependencies.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ def cache_inputs_hash(
pieces.append(fname.encode())
pieces.append(fpath.read_bytes())
except OSError:
# Ignore unreadable dependency files in the cache fingerprint.
pass
if not pieces:
return None
Expand Down Expand Up @@ -192,6 +193,7 @@ def _count_dependencies(repo_path: Path, manifests: list[str]) -> int | None:
dev_deps = len(pkg.get("devDependencies", {}))
return deps + dev_deps
except (json.JSONDecodeError, OSError):
# Unparseable package metadata falls through to other manifest types.
pass

if "requirements.txt" in manifests:
Expand All @@ -205,6 +207,7 @@ def _count_dependencies(repo_path: Path, manifests: list[str]) -> int | None:
and not line.strip().startswith("-")
)
except OSError:
# Unreadable requirements files fall through to other manifest types.
pass

if "Cargo.toml" in manifests:
Expand All @@ -223,6 +226,7 @@ def _count_dependencies(repo_path: Path, manifests: list[str]) -> int | None:
count += 1
return count
except OSError:
# Unreadable Cargo manifests fall through to other manifest types.
pass

if "go.mod" in manifests:
Expand All @@ -240,6 +244,7 @@ def _count_dependencies(repo_path: Path, manifests: list[str]) -> int | None:
count += 1
return count
except OSError:
# Unreadable Go modules fall through to other manifest types.
pass

if "pyproject.toml" in manifests:
Expand All @@ -258,6 +263,7 @@ def _count_dependencies(repo_path: Path, manifests: list[str]) -> int | None:
count += 1
return count if count > 0 else None
except OSError:
# Unreadable pyproject metadata means no dependency count is available.
pass

return None
4 changes: 4 additions & 0 deletions src/analyzers/testing.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ def _detect_test_framework(repo_path: Path) -> str | None:
if "cypress" in all_deps:
return "cypress"
except (json.JSONDecodeError, OSError):
# Unreadable package metadata simply means no JS test runner was detected.
pass

# Python — check pyproject.toml for pytest
Expand All @@ -115,6 +116,7 @@ def _detect_test_framework(repo_path: Path) -> str | None:
if "unittest" in content:
return "unittest"
except OSError:
# Unreadable project metadata simply means no Python test runner was detected.
pass

# Python — check for pytest in requirements
Expand All @@ -126,6 +128,7 @@ def _detect_test_framework(repo_path: Path) -> str | None:
if "pytest" in content:
return "pytest"
except OSError:
# Unreadable requirements files are ignored during best-effort detection.
pass

# Rust — check Cargo.toml for dev-dependencies
Expand All @@ -136,6 +139,7 @@ def _detect_test_framework(repo_path: Path) -> str | None:
if "[dev-dependencies]" in content:
return "cargo-test"
except OSError:
# Unreadable Cargo metadata simply means no Rust test runner was detected.
pass

# Go — test files convention
Expand Down
1 change: 1 addition & 0 deletions src/briefing.py
Original file line number Diff line number Diff line change
Expand Up @@ -388,6 +388,7 @@ def _parse_suggestions_json(raw: str, top_repos: list[dict]) -> list[Suggestion]
result.append(Suggestion(name=name, action=action))
return result
except (json.JSONDecodeError, IndexError, TypeError):
# Fall back to regex extraction when the model response is not valid JSON.
pass

# Regex fallback: extract quoted strings
Expand Down
5 changes: 5 additions & 0 deletions src/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ def _gh_auth_token() -> str | None:
if result.returncode == 0 and result.stdout.strip():
return result.stdout.strip()
except (FileNotFoundError, subprocess.TimeoutExpired):
# Missing or slow gh CLI auth falls back to unauthenticated/public mode.
pass
return None

Expand Down Expand Up @@ -3044,6 +3045,7 @@ def _run_list_initiatives_mode(args) -> None:
if name:
projects_by_name[name.lower()] = proj
except (OSError, ValueError):
# Initiative listing can proceed without portfolio-truth tier context.
pass

open_initiatives = [i for i in initiatives if i.closed_at is None]
Expand Down Expand Up @@ -3076,6 +3078,7 @@ def _run_list_initiatives_mode(args) -> None:
days_left = (date.fromisoformat(initiative.deadline) - date.today()).days
status_detail = f"at-risk (deadline ≤ {days_left}d)"
except ValueError:
# Malformed deadlines keep the generic at-risk label.
pass
elif status == "on-track":
status_detail = "on-track"
Expand Down Expand Up @@ -3598,6 +3601,7 @@ def _run_main_audit_cycle(args, config_inspection) -> None:
resumed_audits.append(_audit_from_dict(audit_dict))
resumed_names.add(audit_dict.get("metadata", {}).get("name", ""))
except Exception:
# Skip corrupt resume entries and continue with the rest.
pass
if resumed_audits:
print_info(f"Resumed {len(resumed_audits)} previously completed repo(s)")
Expand Down Expand Up @@ -4968,6 +4972,7 @@ def _fresh_run(repo_path, meta, conn=None):
try:
_warehouse_conn.close()
except Exception:
# Warehouse close failures are non-actionable during final cleanup.
pass
if _reconcile_diverged:
sys.exit(1)
Expand Down
1 change: 1 addition & 0 deletions src/cloner.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ def _git_askpass_env(token: str | None) -> Generator[dict[str, str] | None, None
try:
script_path.unlink()
except OSError:
# Temporary askpass cleanup is best-effort.
pass


Expand Down
1 change: 1 addition & 0 deletions src/excel_workbook_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ def set_defined_name(wb: Workbook, name: str, attr_text: str) -> None:
try:
del wb.defined_names[name]
except KeyError:
# The defined name may not exist yet.
pass
wb.defined_names.add(DefinedName(name, attr_text=attr_text))

Expand Down
1 change: 1 addition & 0 deletions src/issue_creator.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ def create_audit_issues(
skipped.append(repo_name)
continue
except Exception:
# If issue listing fails, continue and let create_issue surface any hard error.
pass
actions = qw.get("actions", [])
title = f"[Audit] {repo_name}: {actions[0] if actions else 'Improve audit score'}"
Expand Down
3 changes: 3 additions & 0 deletions src/libyears.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ def _parse_pip_deps(path: Path) -> list[tuple[str, str, str]]:
if match:
deps.append((match.group(1), match.group(2), "pypi"))
except OSError:
# Missing or unreadable requirements files have no parseable dependencies.
pass
return deps

Expand All @@ -123,6 +124,7 @@ def _parse_cargo_deps(path: Path) -> list[tuple[str, str, str]]:
if match:
deps.append((match.group(1), match.group(2), "crates"))
except OSError:
# Missing or unreadable Cargo manifests have no parseable dependencies.
pass
return deps

Expand All @@ -144,6 +146,7 @@ def _parse_pyproject_deps(path: Path) -> list[tuple[str, str, str]]:
if match:
deps.append((match.group(1), match.group(3), "pypi"))
except OSError:
# Missing or unreadable pyproject files have no parseable dependencies.
pass
return deps

Expand Down
1 change: 1 addition & 0 deletions src/portfolio_truth_reconcile.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ def _derive_has_tests(project_path: Path | None, has_git: bool) -> bool:
if match:
return True
except StopIteration:
# No matching files for this pattern; try the next pattern.
pass
return False

Expand Down
1 change: 1 addition & 0 deletions src/readme_suggestions.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ def _check_readme(repo_path: Path) -> tuple[str, list[str]]:
try:
content = readme.read_text(errors="replace")
except OSError:
# Unreadable README candidates are treated as absent.
pass
break

Expand Down
10 changes: 10 additions & 0 deletions src/serve/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ async def repo_detail(request: Request, name: str) -> HTMLResponse:
).fetchall()
history = [dict(r) for r in rows]
except sqlite3.Error:
# Optional warehouse history should not block the repo detail page.
pass
finally:
conn.close()
Expand All @@ -158,6 +159,7 @@ async def repo_detail(request: Request, name: str) -> HTMLResponse:
).fetchall()
dimension_scores = [dict(r) for r in rows2]
except sqlite3.Error:
# Optional dimension breakdown should not block the repo detail page.
pass
finally:
conn2.close()
Expand Down Expand Up @@ -197,6 +199,7 @@ async def runs_list(request: Request, page: int = 1) -> HTMLResponse:
).fetchall()
rows = [dict(r) for r in raw]
except sqlite3.Error:
# Runs can render as an empty list when the optional warehouse is unreadable.
pass
finally:
conn.close()
Expand Down Expand Up @@ -224,6 +227,7 @@ async def approvals(request: Request) -> HTMLResponse:
# username is inferred from output_dir contents — use empty string as sentinel
records = load_approval_records(output_dir, username="")
except Exception:
# Approval center is best-effort; the page can render with no records.
pass

return templates.TemplateResponse(
Expand All @@ -249,6 +253,7 @@ async def draft_diff(request: Request, record_id: str) -> HTMLResponse:
None,
)
except Exception:
# Missing/unreadable approval records are handled by the 404 below.
pass

if record is None:
Expand Down Expand Up @@ -291,6 +296,7 @@ async def campaign_plan(request: Request, record_id: str) -> HTMLResponse:
None,
)
except Exception:
# Missing/unreadable campaign records are handled by the 404 below.
pass

if record is None:
Expand Down Expand Up @@ -538,6 +544,7 @@ async def draft_sections(request: Request, packet_id: str) -> HTMLResponse:
key=lambda r: int(r.get("section_idx") or 0),
)
except Exception:
# Missing/unreadable section records are handled by the 404 below.
pass

if not sections:
Expand Down Expand Up @@ -645,6 +652,7 @@ async def initiatives(request: Request) -> HTMLResponse:
if name:
projects_by_name[name] = p
except (json.JSONDecodeError, OSError):
# Initiative list can render without truth-derived tier context.
pass

open_initiatives = [i for i in inits if i.closed_at is None]
Expand Down Expand Up @@ -946,6 +954,7 @@ async def initiative_gap(request: Request, repo_name: str, target: int = 0) -> H
target = init.target_tier
break
except Exception:
# Query parameter target remains authoritative if initiative lookup fails.
pass

# Load portfolio-truth
Expand All @@ -959,6 +968,7 @@ async def initiative_gap(request: Request, repo_name: str, target: int = 0) -> H
if name:
projects_by_name[name] = p
except (json.JSONDecodeError, OSError):
# The route raises a 404 below when truth data cannot be loaded.
pass

repo = projects_by_name.get(repo_name)
Expand Down
1 change: 1 addition & 0 deletions src/web_export.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ def export_html_dashboard(
"top_elevated": _te[:5],
}
except Exception:
# Risk posture is optional enrichment for the HTML export.
pass

html = _render_html(
Expand Down
4 changes: 4 additions & 0 deletions tests/test_draft_readmes.py
Original file line number Diff line number Diff line change
Expand Up @@ -322,8 +322,10 @@ def test_audit_report_draft_readmes_repo_calls_dispatch(self) -> None:
try:
main()
except SystemExit:
# The test only verifies dispatch; CLI exits are expected here.
pass
except Exception:
# The test only verifies dispatch; mocked CLI setup may stop early.
pass
assert mock_dispatch.called

Expand Down Expand Up @@ -383,8 +385,10 @@ def test_legacy_form_emits_deprecation_warning(self) -> None:

main()
except SystemExit:
# The test only verifies legacy routing; CLI exits are expected here.
pass
except Exception:
# The test only verifies legacy routing; mocked setup may stop early.
pass
# Either a DeprecationWarning was emitted or _run_draft_readmes_mode was called
# (both indicate the flag was routed correctly)
Expand Down
8 changes: 8 additions & 0 deletions tests/test_plan_campaign.py
Original file line number Diff line number Diff line change
Expand Up @@ -417,8 +417,10 @@ def test_report_subcommand_calls_run_plan_campaign_mode(self) -> None:

main()
except SystemExit:
# The test only verifies dispatch; CLI exits are expected here.
pass
except Exception: # noqa: BLE001
# The test only verifies dispatch; mocked CLI setup may stop early.
pass
mock_dispatch.assert_called_once()

Expand Down Expand Up @@ -450,8 +452,10 @@ def test_legacy_invocation_emits_deprecation_warning(self) -> None:

main()
except SystemExit:
# The test only verifies warning dispatch; CLI exits are expected here.
pass
except Exception: # noqa: BLE001
# The test only verifies warning dispatch; mocked setup may stop early.
pass
mock_warn.assert_called_once()

Expand Down Expand Up @@ -483,8 +487,10 @@ def test_campaign_from_ledger_dispatches_run_mode(self) -> None:

main()
except SystemExit:
# The test only verifies dispatch; CLI exits are expected here.
pass
except Exception: # noqa: BLE001
# The test only verifies dispatch; mocked CLI setup may stop early.
pass
mock_dispatch.assert_called_once()

Expand Down Expand Up @@ -513,8 +519,10 @@ def test_boot_no_truth_file_exits_cleanly(self) -> None:

main()
except SystemExit:
# The test only verifies clean handling; CLI exits are expected here.
pass
except Exception: # noqa: BLE001
# The test captures output rather than failing on setup noise.
pass


Expand Down