Skip to content
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@


def plain_fallback_body(workflow_name: str, run_url: str) -> str:
"""The plain, generic body text used whenever enrichment is unavailable."""
"""Render the generic body used whenever enrichment is unavailable."""
return f"Scheduled workflow '{workflow_name}' failed: {run_url}"


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
from __future__ import annotations

import json
import subprocess
import subprocess # ruff: ignore[suspicious-subprocess-import] -- see `gh` below
from typing import Any

from . import _summary
Expand All @@ -28,8 +28,14 @@

def gh(*args: str, check: bool = True) -> subprocess.CompletedProcess:
"""Run a `gh` subcommand, returning the completed process."""
# S607: `gh` is deliberately called by name, resolved from the runner's PATH.
return subprocess.run(['gh', *args], text=True, capture_output=True, check=check) # noqa: S607
# The argv is a list this module builds, and `gh` is deliberately called by
# name so the runner's PATH resolves it.
return subprocess.run( # ruff: ignore[subprocess-without-shell-equals-true]
['gh', *args], # ruff: ignore[start-process-with-partial-path]
text=True,
capture_output=True,
check=check,
)


def gh_json(*args: str) -> Any:
Expand Down Expand Up @@ -111,8 +117,7 @@ def fetch_issue_texts(repo: str, number: int) -> list[str]:
"""Fetch an issue's body plus all comment bodies, for marker scanning."""
data = gh_json('issue', 'view', str(number), '--repo', repo, '--json', 'body,comments') or {}
texts = [data.get('body') or '']
for c in data.get('comments') or []:
texts.append(c.get('body') or '')
texts.extend(comment.get('body') or '' for comment in data.get('comments') or [])
return texts


Expand All @@ -138,7 +143,7 @@ def resolve_origin(
issue keeps that lookup to reading the one issue we were handed.
"""
texts = [(notify_issue, text) for text in fetch_issue_texts(repo, notify_issue)]
enriched_issue, origin_kind, origin_issue = find_run_markers(texts, run_id)
enriched_issue, origin_kind, _ = find_run_markers(texts, run_id)
# The passed-in values win: a marker we failed to find on the issue does
# not make the issue the wrong one.
return enriched_issue, notify_origin or origin_kind, notify_issue
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,6 @@ def from_gh(cls, data: dict[str, Any]) -> CandidateIssue:
)

def excerpt(self) -> str:
"""The first line of the body, bounded, for the candidate block."""
"""Return the first line of the body, bounded, for the candidate block."""
lines = (self.body or '').strip().splitlines()
return lines[0][:300] if lines else '(no body)'
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,8 @@ def call_openrouter(
headers={'Authorization': f'Bearer {api_key}', 'Content-Type': 'application/json'},
method='POST',
)
# S310: the URL is a literal https endpoint, not caller-controlled.
with urllib.request.urlopen(request, timeout=60) as response: # noqa: S310
# The URL is a literal https endpoint, not caller-controlled.
with urllib.request.urlopen(request, timeout=60) as response: # ruff: ignore[suspicious-url-open-usage]
body = json.loads(response.read().decode())
content = body['choices'][0]['message']['content']
return json.loads(content)
2 changes: 1 addition & 1 deletion ai-failure-notifier/tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@

from __future__ import annotations

import subprocess
import subprocess # ruff: ignore[suspicious-subprocess-import] -- see `_no_subprocess`
import urllib.request

import pytest
Expand Down
8 changes: 5 additions & 3 deletions ai-failure-notifier/tests/test_ai_failure_notifier.py
Original file line number Diff line number Diff line change
Expand Up @@ -1144,9 +1144,11 @@ def test_http_error_propagates_so_main_can_fall_back(self):
io.BytesIO(b''),
)
self.addCleanup(error.close)
with mock.patch.object(_openrouter.urllib.request, 'urlopen', side_effect=error):
with self.assertRaises(urllib.error.HTTPError):
_openrouter.call_openrouter('sys', 'user', 'm', 'k')
with (
mock.patch.object(_openrouter.urllib.request, 'urlopen', side_effect=error),
self.assertRaises(urllib.error.HTTPError),
):
_openrouter.call_openrouter('sys', 'user', 'm', 'k')


class ResolveOriginTests(unittest.TestCase):
Expand Down