-
Notifications
You must be signed in to change notification settings - Fork 31
checks for gitea PRs based on AMQP messages #272
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
|
@foursixnine fyi |
11ecfd5 to
63cbbc2
Compare
openqabot/amqp.py
Outdated
| try: | ||
| log.info(f"Scheduling jobs for PR {pr_number}") | ||
| error_count = 0 | ||
| for s in settings_data: | ||
| params = { | ||
| "DISTRI": s.distri, | ||
| "VERSION": s.version, | ||
| "FLAVOR": s.flavor, | ||
| "ARCH": s.arch, | ||
| "BUILD": s.build, | ||
| } | ||
| log.info( | ||
| "Scheduling job for %s v%s build %s@%s of flavor %s", s.distri, s.version, s.build, s.arch, s.flavor | ||
| ) | ||
| if self.dry: | ||
| log.info("Dry run - would schedule: %s", params) | ||
| continue | ||
| try: | ||
| self.client.post_job(params) | ||
| except Exception as e: | ||
| log.error("Failed to schedule job with params %s: %s", params, e) | ||
| error_count += 1 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In this case, we'd only would trigger openQA jobs if the build for the given PR is finished and perhaps if qam-openqa-review is within the requested reviewers.
Line 462 of amqp-autogits_workflow_pr_bot-pull_request_review_approved-20251006-154156.json contains an example of a successful build.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
to make sure, the openqa tests should be triggered when
"review": {
"type": "pull_request_review_approved",
"content": "Build successful"
}
is the routing key of this message suse.src.pull_request_review_request.review_requested or is something like suse.src.pull_request_review_request.review_approved?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can't recall tbh
63cbbc2 to
b71f160
Compare
Martchus
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In this form this PR seems rather incomplete. It only seems to do something for a new PR if incident settings are already present on the dashboard. So only if the periodically running pipeline has already done that it would help speed things up. However, then we probably also don't need it anymore.
To be actually useful this approach needed to start with what the "first" pipeline step (gitea-sync) does and only then do the next steps. (For all the steps you can checkout the commands for local testing which basically describe all the steps from creating an incident on the dashboard to the final approval.)
However, you of course had to start somewhere. I guess I would have started from the start creating an incident on the dashboard first but your changes can be extended. The only thing that is really wrong is the duplication of making the scheduling parameters.
By the way, goal 1 of https://progress.opensuse.org/issues/189942 is phrased very openly. So in theory also an approach that doesn't use the dashboard and existing code for computing parameters at all would be acceptable. However, I think if you involve the dashboard (which you did) then the parameters should also be computed using the existing logic. (Then this will basically be another (more event driven) way of doing what we already do with the full dashboard.)
| body: bytes, | ||
| ) -> None: | ||
| log.info("%s - Received openQA job message", method.routing_key) | ||
| log.debug(" %s - %s", method.routing_key, body.decode()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| log.debug(" %s - %s", method.routing_key, body.decode()) | |
| log.debug("%s - %s", method.routing_key, body.decode()) |
And we probably don't want method.routing_key again as it is already covered by the previous log message.
The same applies to the other occurrence.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
space was intentional.
about the method.routing_key, I want it to be visible in the logs. if the amqp do not run with --queue it will be harder to spot where are the message coming from. there a logging formatter or something, but I didnt want to go that far for this ticket. it is supposed to show what I have in mind for the task, but not cover everything in the given timebox period.
openqabot/amqp.py
Outdated
| log.info("%s - Received openQA job message", method.routing_key) | ||
| log.debug(" %s - %s", method.routing_key, body.decode()) | ||
| message = json.loads(body) | ||
| if self.args.dry: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would make more sense to handle self.args.dry in a deeper level (maybe self.handle_incident) to we still run as much code as possible with --dry.
openqabot/amqp.py
Outdated
| properties: pika.spec.BasicProperties, # noqa: ARG002 Unused method argument | ||
| body: bytes, | ||
| ) -> None: | ||
| log.info("%s - Received gitea review request message", method.routing_key) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| log.info("%s - Received gitea review request message", method.routing_key) | |
| log.info("%s - Received Gitea review request message", method.routing_key) |
openqabot/amqp.py
Outdated
| log.info("%s - Received gitea review request message", method.routing_key) | ||
| log.debug(" %s - %s", method.routing_key, body.decode()) | ||
| message = json.loads(body) | ||
| if self.args.dry: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Again, this could and should probably be handled at a deeper level.
openqabot/amqp.py
Outdated
| if not pr_number: | ||
| log.error("Could not extract PR number from AMQP message") | ||
| return |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think int will throw a ValueError but never 0 (or another falsy value) if an argument is given. So this error handling is dead code.
tests/fixtures/qembot_mocks.py
Outdated
|
|
||
|
|
||
| @pytest.fixture | ||
| def qem_mock_get_incident_settings() -> Any: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| def qem_mock_get_incident_settings() -> Any: | |
| def mock_get_incident_settings() -> Any: |
or
| def qem_mock_get_incident_settings() -> Any: | |
| def mock_qem_get_incident_settings() -> Any: |
The same applies to other functions. I'd still always start with mock_ for functions which do mocking and keep the location/name of the function being mocked together.
tests/fixtures/qembot_mocks.py
Outdated
| """Fixture providing a mock for get_incident_settings_data function. | ||
| to make it function in multiple other test, as `get_incident_settings_data` you | ||
| and making it reusable across all tests append the patch with teh other places. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please fix the spelling mistakes. If you don't want to, simply remove this whole documentation. We don't need documentation for this kind of function. Its name and location already tell what it is for so this whole paragraph doesn't add much value anyway.
tests/fixtures/qembot_mocks.py
Outdated
| reviewer: The username of the requested reviewer (default: "qam-openqa-review") | ||
| Returns: | ||
| A json-encoded bytes object of gitea review request message |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| A json-encoded bytes object of gitea review request message | |
| A JSON-encoded bytes object of a Gitea review request message |
tests/fixtures/qembot_mocks.py
Outdated
| @pytest.fixture | ||
| def gitea_mock_review_request_body() -> Any: | ||
| """Mock the review request body for Gitea responses. | ||
| Here is the minimum requirement for amqp event handling... |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's something missing here. However, I'm wondering whether we really need this lengthy documentation with even examples in the first place? It really doesn't add anything you can't just infer from looking a the names of the function and its arguments.
So I suggest: Keep it short and without typos or avoid these kinds of documentations.
By the way, a short version would be:
"Returns the review request body for the Gitea PR with the specified number and reviewer as JSON-encoded bytes object."
| # Check fixtures in tests/fixtures/qembot_mocks.py | ||
| # imported from conftest.py |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Where is this actually imported? If it isn't imported anywhere after all, then this comment should probably be removed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is the term import the problem here? I just want to let you know where to find the mocks if you come in the the test for first time.
But they are imported in the conftest.
https://docs.pytest.org/en/7.1.x/reference/fixtures.html#conftest-py-sharing-fixtures-across-multiple-files
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To me it wasn't even clear that these two lines from a whole sentence. What about using correct punctuation once in a while?
And it is also not clear that this is telling someone to check something. Normally comments describe what the code does in case that's not obvious. So rather say:
Fixtures for this test are imported via
conftesyt.pyand can be found intests/fixtures/qembot_mocks.py.
|
I push some changes. I will review/answer the comments tomorrow |
3c39842 to
5a8e15f
Compare
Extend the amqp module with a separate queue for the gitea PRs. Following the existing design which provides the logic and the flexibility to orchestrate the event handling according their purpose. The existing queue is listening for suse.openqa events and nothing has changed in this flow, except some small tweaks, which most significant, to prevent normal execution when `dry` is enabled. All the events from `suse.src.pull_request_review_request.review_requested` should activate `handle_inc_review_request` which its rensposibility is to schedule jobs. This is true if the data contains `qam-openqa-review` in the reviewers. Here there are a few option, depending on the way the updates are being updated. - `do_incident_schedule` will check the dashboard and schedule everything. - `IncrementApprover._schedule_openqa_jobs` but it is an instance method - Likely the best option is to call `post_job` from openQAInterface The command line is append with `--queue` in order to be able to run the amqp command against a particular queue if this is wanted. However by default it initializes both defined queues. issue: https://progress.opensuse.org/issues/189942 Signed-off-by: Ioannis Bonatakis <[email protected]>
5a8e15f to
95c8adf
Compare
- Create fixtures for `get_incident_settings_data` and `post_job` - Setup provision of the mocks and fixtures to all the tests And tests cover: - a smoke test for dry_run - the positive scenario - and a negative scenarion where the `qam-openqa-review` is not in the reviewer issue: https://progress.opensuse.org/issues/189942 Signed-off-by: Ioannis Bonatakis <[email protected]>
95c8adf to
b5908a4
Compare
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #272 +/- ##
==========================================
- Coverage 75.12% 74.91% -0.22%
==========================================
Files 32 32
Lines 2730 2794 +64
==========================================
+ Hits 2051 2093 +42
- Misses 679 701 +22 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
Depending on the service the scope is changing. For rabbit.suse.de is always `suse` and for rabbit.opensuse.org is always `opensuse`. So this commit allows to catch all the events despite which AMQP_URL is used. issue: https://progress.opensuse.org/issues/189942
9db60f7 to
79fbfee
Compare
To avoid depending on dashboard to get incident data, the handle_inc_review_request was refactored to make use of the `Incident` Class. The instance should compute the required variables to make a direct job_post and schedule job groups. Some variables are still hardcoded. And some bits might still missing, but the implementation attempts to reuse existing functionality. Tests have been adjusted. But there are unused mocks. Left intentionally in a place which tests can make use of them in the future, as they mock common function(s). issue: https://progress.opensuse.org/issues/189942 Signed-off-by: Ioannis Bonatakis <[email protected]>
79fbfee to
f4a14db
Compare
| return | ||
| routing_keys = { | ||
| "openqa": ("*.openqa.#", self.on_job_message), | ||
| "gitea": ("*.pull_request_review_request.#", self.on_review_request), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Keep in mind that the event you should be looking for, is the PR approval by the bot: https://src.opensuse.org/products/PackageHub/pulls/213#issuecomment-51757 (at least for openSUSE, Looks like for SLE is the same story) because it tells you that the build has finished, and is ok to trigger tests, otherwise the build might not be finished and the tests will fail.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the requirement is satisfied here https://github.com/openSUSE/qem-bot/pull/272/files#diff-78f57cc644e149681a7b2cc5aab3776d91e8ee1ccca16f29016ab983a5d46db5R115. specifically,
def _has_build_succeeded() -> bool:
review_tag = message.get("review", "")
if not review_tag or review_tag == "null":
return False
is_type_approved = review_tag.get("type") == "pull_request_review_approved"
is_build_success = review_tag.get("content") == "Build successful"
return is_type_approved and is_build_success| log.debug(" %s - %s", method.routing_key, body.decode()) | ||
| message = json.loads(body) | ||
|
|
||
| def _has_build_succeeded() -> bool: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would also check that the user is autogits_obs_staging_bot
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok. But why? at the point where the _has_build_succeeded, why do I need the user? he has done whatever he has to do, no?
Add a handler on dedicate queue which will schedule openQA jobs on gitea review requests, if
qam-openqa-reviewis part of the reviewers.This is more or less upon the
amqp-listen-giteahttps://github.com/os-autoinst/os-autoinst-scripts/pull/468/files but without boilerplate of openqa, as the qem-bot already implements interface to openQA.Using an additional parameter we can invoke the listener with a particular queue.
Without
--queueboth queues are created.It would be nice to have an accordingly named queue but I didnt implement this. each queue receives automatically a generated name.
Now IIUC
handle_incidentretrieves inc settings and then tries to schedule job for each. So I couldnt use it directly. in my understanding, the review_request must trigger scheduler for particular set of settings. I am not sure ifhandle_inc_review_requesthandles this properly. it assumes that still the settings will be found in the dashboard and therefore it tries to fetch them using the same request.I test this manual and following with some basic tests. I run the amqp command again as I write this, but I have no results yet. listening only to
suse.src.pull_request_review_request.review_requested. this might be a little strict. I think the rabbitmq returns something which we can handle if we want to check that it does something underneath.issue: https://progress.opensuse.org/issues/189942