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 snap/snapcraft.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ environment:
PYTHONPATH: "$PYTHONPATH:$SNAP/usr/lib/python3/dist-packages"
# prevent lstopo from hanging on 26.04
HWLOC_COMPONENTS: "-gl"
PYTHONOPTIMIZE: '1'
Comment thread
tomli380576 marked this conversation as resolved.

layout:
# this combined with the 'cp' in the install hook
Expand Down
3 changes: 2 additions & 1 deletion src/bugit_v2/apps/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -387,7 +387,8 @@ def main(
):
sudo_devmode_check()
ensure_all_directories_exist()
assert ctx.command.name in ("lp", "jira", "local")
if ctx.command.name not in ("lp", "jira", "local"):
raise RuntimeError(f"Unexpected command name: {ctx.command.name!r}")

if checkbox_submission:
print(f"Decompressing checkbox submission at {checkbox_submission}")
Expand Down
30 changes: 20 additions & 10 deletions src/bugit_v2/bug_report_submitters/jira_submitter.py
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,8 @@ def project_exists(self, project_name: str) -> None:
https://hostname.com/jira/software/c/projects/NAME
:return: true if the project exists
"""
assert self.jira, "Jira client is not initialized"
if not self.jira:
raise JiraSubmitterError("Jira client is not initialized")
try:
self.jira.project(id=project_name)
except Exception:
Expand All @@ -186,7 +187,8 @@ def assignee_exists_and_unique(self, assignee: str) -> str:
:param assignee: the email of the assignee or some form of ID
:return: exists and unique
"""
assert self.jira, "Jira client is not initialized"
if not self.jira:
raise JiraSubmitterError("Jira client is not initialized")

query_result = self.jira.search_users(query=assignee)
if len(query_result) == 0:
Expand All @@ -198,7 +200,8 @@ def assignee_exists_and_unique(self, assignee: str) -> str:
return query_result[0].accountId # pyright: ignore[reportAny]

def all_components_exist(self, project: str, components: Sequence[str]) -> None:
assert self.jira, "Jira client is not initialized"
if not self.jira:
raise JiraSubmitterError("Jira client is not initialized")
# the @translate_args decorator confuses the type checker
query_result = cast(list[Component], self.jira.project_components(project))
for wanted_component in components:
Expand All @@ -214,7 +217,8 @@ def all_components_exist(self, project: str, components: Sequence[str]) -> None:

@override
def bug_exists(self, bug_id: str) -> bool:
assert self.auth
if not self.auth:
raise JiraSubmitterError("Missing auth credentials")

try:
if not self.jira:
Expand Down Expand Up @@ -273,8 +277,10 @@ def submit(

bug_dict["description"] = content_str

assert self.auth, "Missing auth credentials"
assert JIRA_SERVER_ADDRESS, "JIRA_SERVER is not specified!"
if not self.auth:
raise JiraSubmitterError("Missing auth credentials")
if not JIRA_SERVER_ADDRESS:
raise JiraSubmitterError("JIRA_SERVER is not specified!")

yield "Starting Jira authentication..."
self.jira = JIRA(
Expand Down Expand Up @@ -330,17 +336,21 @@ def get_cached_credentials(self) -> JiraBasicAuth | None:
def upload_attachment(
self, attachment_file: Path, filename: str | None = None
) -> None:
assert self.jira
assert self.issue
if not self.jira:
raise JiraSubmitterError("Jira client is not initialized")
if not self.issue:
raise JiraSubmitterError("Nothing has been submitted to Jira yet")
# .add_attachment has a decorator that confuses the typechecker
# go to its definition to see the expected arguments
self.jira.add_attachment(self.issue.id, str(attachment_file), filename)

@property
@override
def bug_url(self) -> str:
assert self.jira
assert self.issue, "Nothing has been submitted to Jira yet"
if not self.jira:
raise JiraSubmitterError("Jira client is not initialized")
if not self.issue:
raise JiraSubmitterError("Nothing has been submitted to Jira yet")
return f"{self.jira.server_url}/browse/{self.issue.key}"

@override
Expand Down
51 changes: 33 additions & 18 deletions src/bugit_v2/bug_report_submitters/launchpad_submitter.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,11 @@
)
LP_APP_NAME = os.getenv("BUGIT_APP_NAME", "bugit-v2")

assert SERVICE_ROOT in VALID_SERVICE_ROOTS
if SERVICE_ROOT not in VALID_SERVICE_ROOTS:
raise RuntimeError(
"Invalid APPORT_LAUNCHPAD_INSTANCE, "
f"expected one of {VALID_SERVICE_ROOTS}, but got {SERVICE_ROOT}"
)


@final
Expand Down Expand Up @@ -167,11 +171,13 @@ def on_mount(self):

@work(thread=True)
def main_auth_sequence(self):
assert SERVICE_ROOT in VALID_SERVICE_ROOTS, (
"Invalid APPORT_LAUNCHPAD_INSTANCE, "
f"expected one of {VALID_SERVICE_ROOTS}, but got {SERVICE_ROOT}"
)
assert LP_APP_NAME, "BUGIT_APP_NAME was not specified"
if SERVICE_ROOT not in VALID_SERVICE_ROOTS:
raise RuntimeError(
"Invalid APPORT_LAUNCHPAD_INSTANCE, "
f"expected one of {VALID_SERVICE_ROOTS}, but got {SERVICE_ROOT}"
)
if not LP_APP_NAME:
raise RuntimeError("BUGIT_APP_NAME was not specified")

log_widget = self.query_exactly_one("#lp_login_stdout", RichLog)
auth_engine = GraphicalAuthorizeRequestTokenWithURL(
Expand Down Expand Up @@ -244,7 +250,8 @@ class LaunchpadSubmitter(BugReportSubmitter[Path]):
lp_bug_object: Any | None = None # TODO: make a wrapper for this

def check_project_existence(self, project_name: str) -> Any:
assert self.lp_client
if not self.lp_client:
raise RuntimeError("Launchpad client is not initialized")
try:
# type checker freaks out here
# since launchpad lib wants unknown member access + index access
Expand All @@ -259,7 +266,8 @@ def check_project_existence(self, project_name: str) -> Any:
raise ValueError(error_message)

def check_assignee_existence(self, assignee: str) -> Any:
assert self.lp_client
if not self.lp_client:
raise RuntimeError("Launchpad client is not initialized")
try:
return self.lp_client.people[ # pyright: ignore[reportIndexIssue, reportOptionalSubscript, reportUnknownVariableType]
assignee
Expand All @@ -269,7 +277,8 @@ def check_assignee_existence(self, assignee: str) -> Any:
raise ValueError(error_message)

def check_series_existence(self, series: str) -> Any:
assert self.lp_client
if not self.lp_client:
raise RuntimeError("Launchpad client is not initialized")
try:
return self.lp_client.project.getSeries( # pyright: ignore[reportAttributeAccessIssue, reportOptionalMemberAccess, reportUnknownVariableType]
name=series
Expand All @@ -286,12 +295,15 @@ def bug_exists(self, bug_id: str) -> bool:
def submit(
self, bug_report: BugReport
) -> Generator[str | AdvanceMessage, None, None]:
assert SERVICE_ROOT in VALID_SERVICE_ROOTS, (
"Invalid APPORT_LAUNCHPAD_INSTANCE, "
f"expected one of {VALID_SERVICE_ROOTS}, but got {SERVICE_ROOT}"
)
assert LP_APP_NAME, "BUGIT_APP_NAME was not specified"
assert LP_AUTH_FILE_PATH.exists(), "At this point auth should already be valid"
if SERVICE_ROOT not in VALID_SERVICE_ROOTS:
raise RuntimeError(
"Invalid APPORT_LAUNCHPAD_INSTANCE, "
f"expected one of {VALID_SERVICE_ROOTS}, but got {SERVICE_ROOT}"
)
if not LP_APP_NAME:
raise RuntimeError("BUGIT_APP_NAME was not specified")
if not LP_AUTH_FILE_PATH.exists():
raise RuntimeError("At this point auth should already be valid")

yield f"Logging into Launchpad: {SERVICE_ROOT}"
try:
Expand Down Expand Up @@ -368,7 +380,8 @@ def submit(
bug_report.project # index access also has a side effect
],
)
assert self.lp_bug_object, "Unexpected null bug"
if not self.lp_bug_object:
raise RuntimeError("Unexpected null bug")
# https://documentation.ubuntu.com/launchpad/user/explanation/launchpad-api/launchpadlib/#persistent-references-to-launchpad-objects
yield AdvanceMessage(
f"Created bug: {self.lp_bug_object!s}" # pyright: ignore[reportUnknownArgumentType]
Expand Down Expand Up @@ -399,7 +412,8 @@ def submit(
def upload_attachment(
self, attachment_file: Path, filename: str | None = None
) -> str | None:
assert self.lp_bug_object, "No launchpad bug has been created or fetched"
if not self.lp_bug_object:
raise RuntimeError("No launchpad bug has been created or fetched")
with open(attachment_file, "rb") as f:
# this might explode on low memory systems
# but idk how to work around it
Expand All @@ -412,7 +426,8 @@ def upload_attachment(
@property
@override
def bug_url(self) -> str:
assert self.lp_bug_object, "No launchpad bug has been created or fetched"
if not self.lp_bug_object:
raise RuntimeError("No launchpad bug has been created or fetched")
match SERVICE_ROOT:
case "production":
return f"{LPNET_WEB_ROOT}bugs/{self.lp_bug_object.id}"
Expand Down
11 changes: 8 additions & 3 deletions src/bugit_v2/bug_report_submitters/local_file_submitter.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,12 +109,14 @@ def get_cached_credentials(self) -> None:
@property
@override
def bug_url(self) -> str:
assert self.archive_path, "Report archive not created"
if not self.archive_path:
raise FileNotFoundError("Report archive not created")
return str(self.archive_path)

@override
def finalize(self) -> str:
assert self.archive_name, "Unexpected call before archive name was determined"
if not self.archive_name:
raise RuntimeError("Unexpected call before archive name was determined")

working_dir = Path(self.working_dir.name)

Expand All @@ -126,7 +128,10 @@ def finalize(self) -> str:
format="gztar",
)
)
assert self.archive_path.exists()
if not self.archive_path.exists():
raise FileNotFoundError(
f"Archive {self.archive_path} was not created as expected"
)
self.finalize_ok = True
return f"The bug report archive is at {self.archive_path}"
except Exception as e:
Expand Down
21 changes: 14 additions & 7 deletions src/bugit_v2/bug_report_submitters/mock_jira.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,8 @@ def project_exists(self, project_name: str) -> None:
https://hostname.com/jira/software/c/projects/NAME
:return: true if the project exists
"""
assert self.jira, "Jira object is not initialized"
if not self.jira:
raise JiraSubmitterError("Jira object is not initialized")
try:
self.jira.project(id=project_name)
except Exception:
Expand All @@ -66,7 +67,8 @@ def assignee_exists_and_unique(self, assignee: str) -> None:
:param assignee: the email of the assignee or some form of ID
:return: exists and unique
"""
assert self.jira, "Jira object is not initialized"
if not self.jira:
raise JiraSubmitterError("Jira object is not initialized")

query_result = self.jira.search_users(query=assignee)
if len(query_result) == 0:
Expand All @@ -75,7 +77,8 @@ def assignee_exists_and_unique(self, assignee: str) -> None:
raise JiraSubmitterError(f"Assignee '{assignee}' isn't unique!")

def all_components_exist(self, project: str, components: Sequence[str]) -> None:
assert self.jira, "Jira object is not initialized"
if not self.jira:
raise JiraSubmitterError("Jira object is not initialized")
# the @translate_args decorator confuses the type checker
query_result = cast(list[Component], self.jira.project_components(project))
for wanted_component in components:
Expand All @@ -89,7 +92,8 @@ def all_components_exist(self, project: str, components: Sequence[str]) -> None:

@override
def bug_exists(self, bug_id: str) -> bool:
assert self.auth
if not self.auth:
raise JiraSubmitterError("Missing auth credentials")

try:
if not self.jira:
Expand Down Expand Up @@ -123,8 +127,10 @@ def submit(
"issuetype": {"name": "Bug"},
}

assert self.auth, "Missing auth credentials"
assert JIRA_SERVER_ADDRESS, "JIRA_SERVER is not specified!"
if not self.auth:
raise JiraSubmitterError("Missing auth credentials")
if not JIRA_SERVER_ADDRESS:
raise JiraSubmitterError("JIRA_SERVER is not specified!")

yield "Starting Jira authentication..."
self.jira = JIRA(
Expand Down Expand Up @@ -190,7 +196,8 @@ def upload_attachment(
@property
@override
def bug_url(self) -> str:
assert self.mock_issue
if not self.mock_issue:
raise JiraSubmitterError("Nothing has been submitted to Jira yet")
return "http://example.com/"

@override
Expand Down
24 changes: 15 additions & 9 deletions src/bugit_v2/bug_report_submitters/mock_lp.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ class MockLaunchpadSubmitter(BugReportSubmitter[Path]):
auth_modal = LaunchpadAuthModal

def check_project_existence(self, project_name: str) -> Any:
assert self.lp_client
if not self.lp_client:
raise RuntimeError("Launchpad client is not initialized")
try:
# type checker freaks out here
# since launchpad lib wants unknown member access + index access
Expand All @@ -55,7 +56,8 @@ def check_project_existence(self, project_name: str) -> Any:
raise ValueError(error_message)

def check_assignee_existence(self, assignee: str) -> Any:
assert self.lp_client
if not self.lp_client:
raise RuntimeError("Launchpad client is not initialized")
try:
return self.lp_client.people[ # pyright: ignore[reportIndexIssue, reportOptionalSubscript, reportUnknownVariableType]
assignee
Expand All @@ -65,7 +67,8 @@ def check_assignee_existence(self, assignee: str) -> Any:
raise ValueError(error_message)

def check_series_existence(self, series: str) -> Any:
assert self.lp_client
if not self.lp_client:
raise RuntimeError("Launchpad client is not initialized")
try:
return self.lp_client.project.getSeries( # pyright: ignore[reportAttributeAccessIssue, reportOptionalMemberAccess, reportUnknownVariableType]
name=series
Expand All @@ -83,12 +86,15 @@ def submit(
self, bug_report: BugReport
) -> Generator[str | AdvanceMessage, None, None]:

assert SERVICE_ROOT in VALID_SERVICE_ROOTS, (
"Invalid APPORT_LAUNCHPAD_INSTANCE, "
f"expected one of {VALID_SERVICE_ROOTS}, but got {SERVICE_ROOT}"
)
assert LP_APP_NAME, "BUGIT_APP_NAME was not specified"
assert LP_AUTH_FILE_PATH.exists(), "At this point auth should already be valid"
if SERVICE_ROOT not in VALID_SERVICE_ROOTS:
raise RuntimeError(
"Invalid APPORT_LAUNCHPAD_INSTANCE, "
f"expected one of {VALID_SERVICE_ROOTS}, but got {SERVICE_ROOT}"
)
if not LP_APP_NAME:
raise RuntimeError("BUGIT_APP_NAME was not specified")
if not LP_AUTH_FILE_PATH.exists():
raise RuntimeError("At this point auth should already be valid")

yield f"Logging into Launchpad: {SERVICE_ROOT}"
try:
Expand Down
3 changes: 2 additions & 1 deletion src/bugit_v2/checkbox_utils/checkbox_exec.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,8 @@ async def checkbox_exec(
:return: whatever subprocess.run returns
"""
checkbox_info = get_checkbox_info()
assert checkbox_info, "Unable to find checkbox on this DUT"
if not checkbox_info:
raise RuntimeError("Unable to find checkbox on this DUT")

logger.info(f"Checkbox args: {checkbox_args}")
if additional_env:
Expand Down
6 changes: 5 additions & 1 deletion src/bugit_v2/checkbox_utils/submission_extractor.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,12 @@

def read_simple_submission(submission_path: Path) -> SimpleCheckboxSubmission:
with tarfile.open(submission_path, "r:xz") as f:
# .extractfile raises KeyError if the file is not in the tar
json_io_reader = f.extractfile("submission.json")
assert json_io_reader, f"submission.json does not exist in {submission_path}"
if not json_io_reader:
raise FileNotFoundError(
f"submission.json exists, but it's not a regular file in {submission_path}"
)
Comment thread
tomli380576 marked this conversation as resolved.
return SimpleCheckboxSubmission(
submission_path.absolute(),
BaseSimpleCheckboxSubmission.model_validate(
Expand Down
3 changes: 2 additions & 1 deletion src/bugit_v2/components/confirm_dialog.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,5 +52,6 @@ def on_mount(self) -> None:
self.query_exactly_one(f"#{self.focus_id_on_mount}", Button).focus()

def on_button_pressed(self, event: Button.Pressed) -> None:
assert event.button.id
if not event.button.id:
raise RuntimeError("Button pressed without an id")
self.dismiss(cast(T, event.button.id))
3 changes: 2 additions & 1 deletion src/bugit_v2/components/file_picker.py
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,8 @@ def on_mount(self):

@on(Button.Pressed, ".delete_selection")
def delete_file_from_list(self, event: Button.Pressed):
assert event.button.name is not None
if event.button.name is None:
raise RuntimeError("Delete button is missing its file name")
try:
self._chosen_files.remove(Path(event.button.name))
self.post_message(self.FilesUpdated(list(self._chosen_files)))
Expand Down
Loading