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
28 changes: 19 additions & 9 deletions openqabot/incrementapprover.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
from .loader.sourcereport import compute_packages_of_request_from_source_report
from .repodiff import Package, RepoDiff
from .requests import find_request_on_obs
from .types.increment import ApprovalStatus, BuildInfo
from .types.increment import ApprovalStatus, BuildInfo, ScheduleParams
from .utils import merge_dicts

if TYPE_CHECKING:
Expand All @@ -42,7 +42,6 @@

OpenQAResult = dict[str, dict[str, dict[str, Any]]]
OpenQAResults = list[OpenQAResult]
ScheduleParams = list[dict[str, str]]


class IncrementApprover:
Expand Down Expand Up @@ -96,10 +95,10 @@ def get_regex_match(pattern: str, string: str) -> re.Match | None:
)
return match

def request_openqa_job_results(self, params: ScheduleParams, info_str: str) -> OpenQAResults:
"""Fetch results from openQA for the specified scheduling parameters."""
log.debug("Checking openQA job results for %s", info_str)
query_params = (
@staticmethod
def _make_search_params(params: ScheduleParams) -> list[dict[str, Any]]:
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we are going in circles here . ScheduleParams is list[dict[str, Any]] and we have function which is "converting" list into list . Can you elaborate why do we need this ?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not about converting types but about turning params (scheduling parameters) into the corresponding search query parameters for the openQA API. Note that this conversion was already there before; I'm just extracting it into a function because I now need it a 2nd time and didn't want to duplicate it.

Copy link
Copy Markdown
Contributor

@asmorodskyi asmorodskyi Mar 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok then it should be method of class ScheduleParams

"""Return search parameters used with the openQA `isos` routes for the specified scheduling parameters."""
return [
{
"distri": p["DISTRI"],
"version": p["VERSION"],
Expand All @@ -109,8 +108,12 @@ def request_openqa_job_results(self, params: ScheduleParams, info_str: str) -> O
"product": p.get("PRODUCT"),
}
for p in params
)
res = [self.client.get_scheduled_product_stats(p) for p in query_params]
]

def request_openqa_job_results(self, params: ScheduleParams, info_str: str) -> OpenQAResults:
"""Fetch results from openQA for the specified scheduling parameters."""
log.debug("Checking openQA job results for %s", info_str)
res = [self.client.get_scheduled_product_stats(p) for p in self._make_search_params(params)]
log.debug("Job statistics:\n%s", pformat(res))
return res

Expand Down Expand Up @@ -175,6 +178,10 @@ def approve_on_obs(self, reqid: str, msg: str) -> None:
message=msg,
)

def _update_scheduled_product_note(self, approval_status: ApprovalStatus, note: str) -> None:
for params in self._make_search_params(approval_status.params):
self.client.update_scheduled_product_note(params, note)

def handle_approval(self, approval_status: ApprovalStatus) -> int:
"""Process approval or disapproval based on job results."""
reasons_to_disapprove = approval_status.reasons_to_disapprove
Expand All @@ -188,10 +195,12 @@ def handle_approval(self, approval_status: ApprovalStatus) -> int:
results_str = "/".join(sorted(ok_results))
message = f"All {len(approval_status.ok_jobs)} openQA jobs have {results_str}"
self.approve_on_obs(str(reqid), message)
self._update_scheduled_product_note(approval_status, f"Approving {reqid}: {message}")
log.info("Approving %s: %s", id_msg, message)
else:
reasons_str = "\n\t".join(reasons_to_disapprove)
end_str = f"End of reasons for not approving {id_msg}"
self._update_scheduled_product_note(approval_status, f"Not approving {reqid}: {reasons_str}")
log.info("Not approving %s for the following reasons:\n\t%s\n%s", id_msg, reasons_str, end_str)
return 0

Expand Down Expand Up @@ -417,6 +426,7 @@ def process_build_info(
"""Process a single build and update its approval status."""
error_count = 0
params = self.make_scheduling_parameters(request, config_inc, build_info)
approval_status.params.extend(params)
log.debug("Prepared scheduling parameters: %s", params)
if len(params) < 1:
log.info("Skipping %s for %s, filtered out via 'packages' or 'archs' setting", config_inc, build_info)
Expand Down Expand Up @@ -455,7 +465,7 @@ def _get_approval_status(self, request: osc.core.Request) -> ApprovalStatus:
if request_id in self.requests_to_approve:
return self.requests_to_approve[request_id]

status = ApprovalStatus(request, set(), [])
status = ApprovalStatus(request, set(), [], [])
self.requests_to_approve[request_id] = status
return status

Expand Down
6 changes: 6 additions & 0 deletions openqabot/openqa.py
Original file line number Diff line number Diff line change
Expand Up @@ -146,3 +146,9 @@ def get_older_jobs(self, job_id: int, limit: int) -> dict:
def get_scheduled_product_stats(self, params: dict[str, Any]) -> dict[str, Any]:
"""Fetch scheduling statistics for a product."""
return self.openqa.openqa_request("GET", "isos/job_stats", params, retries=self.retries)

def update_scheduled_product_note(self, search_params: dict[str, Any], note: str) -> None:
"""Update the note of a scheduled product."""
params = search_params.copy()
params["note"] = note
return self.openqa.openqa_request("PUT", "experimental/isos/note", params, retries=self.retries)
6 changes: 5 additions & 1 deletion openqabot/types/increment.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,17 @@
from __future__ import annotations

from logging import getLogger
from typing import TYPE_CHECKING, NamedTuple
from typing import TYPE_CHECKING, ClassVar, NamedTuple

if TYPE_CHECKING:
import osc.core

log = getLogger("bot.increment_approver")


ScheduleParams = list[dict[str, str]]


class BuildInfo(NamedTuple):
"""Information about a build."""

Expand Down Expand Up @@ -57,6 +60,7 @@ class ApprovalStatus(NamedTuple):
request: osc.core.Request
ok_jobs: set[int]
reasons_to_disapprove: list[str]
params: ClassVar[ScheduleParams] = []

def add(self, ok_jobs: set[int], reasons_to_disapprove: list[str]) -> None:
"""Add jobs and reasons to the status."""
Expand Down
Loading