From 6e5f4110651b92914b6567306f1ac2615b0c8d08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tina=20M=C3=BCller?= Date: Tue, 16 Sep 2025 21:13:37 +0200 Subject: [PATCH 01/14] PoC: Add script to listen for AMQP review requests Issue: https://progress.opensuse.org/issues/185491 --- amqp-listen-gitea.py | 226 +++++++++ ...xample-payload-gitea-review-requested.json | 437 ++++++++++++++++++ ...inimal-payload-gitea-review-requested.json | 26 ++ tests/test_amqp.py | 164 +++++++ 4 files changed, 853 insertions(+) create mode 100644 amqp-listen-gitea.py create mode 100644 tests/data/gitea-amqp/example-payload-gitea-review-requested.json create mode 100644 tests/data/gitea-amqp/minimal-payload-gitea-review-requested.json create mode 100644 tests/test_amqp.py diff --git a/amqp-listen-gitea.py b/amqp-listen-gitea.py new file mode 100644 index 00000000..40a936f0 --- /dev/null +++ b/amqp-listen-gitea.py @@ -0,0 +1,226 @@ +#!/usr/bin/env python3 +import pika +import sys +import os +import argparse +import json +import subprocess +import requests +import re +import logging + +USER_AGENT = 'amqp-listen-gitea.py (https://github.com/os-autoinst/scripts)' +dry_run=False + +logging.basicConfig() +log = logging.getLogger(sys.argv[0] if __name__ == "__main__" else __name__) + +def parse_args(): + parser = argparse.ArgumentParser() + parser.add_argument("--url", help="AMQP URL", default="amqps://opensuse:opensuse@rabbit.opensuse.org") + parser.add_argument("--prefix", help="Event prefix to collect", default="opensuse.src.") + parser.add_argument("--event-type", help="Event type to collect", default="pull_request_review_request.review_requested") + parser.add_argument("--myself", help="Username of bot", default="qam-openqa") + parser.add_argument("--verbose", help="Verbosity", default="1", type=int, choices=[0, 1, 2, 3]) + parser.add_argument("--simulate-review-requested-event", help="Behave as if a pull_request_review_request.review_requested was received") + args = parser.parse_args() + return args + + +def listen(args): + connection = pika.BlockingConnection(pika.URLParameters(args.url)) + channel = connection.channel() + channel.exchange_declare(exchange='pubsub', exchange_type='topic', passive=True, durable=True) + result = channel.queue_declare("", exclusive=True) + queue_name = result.method.queue + channel.queue_bind(exchange='pubsub', queue=queue_name,routing_key='#') + + def cb(ch, method, properties, body): + callback(ch, method, properties, body, args) + channel.basic_consume(queue_name, cb, auto_ack=True) + + print('[*] Waiting for logs. To exit press CTRL+C') + channel.start_consuming() + + +def callback(ch, method, properties, body, args): + # opensuse.src.someuser.pull_request_review_request.review_requested + if not method.routing_key.startswith(args.prefix): + if args.verbose >= 3: + print(" [ ] %r" % (method.routing_key)) + return + if args.event_type not in method.routing_key: + if args.verbose >= 2: + print(" [ ] %r" % (method.routing_key)) + return + if args.verbose >= 2: + print(" [x] %r" % (method.routing_key)) + data = json.loads(body) + handle_review_request(data, args) + + +def simulate(args): + print('================= simulate') + # json_file = 'tests/data/gitea-amqp/minimal-payload-gitea-review-requested.json' + json_file = args.simulate_review_requested_event + with open(json_file, 'r') as f: + content = f.read() + data = json.loads(content) + handle_review_request(data, args) + + +def handle_review_request(data, args): + print("============== handle_review_request") + myself = args.myself + requested_reviewer = data['requested_reviewer']['username'] + if args.verbose >= 1: + print(" [x] Requested review from %r" % (requested_reviewer)) + if requested_reviewer != myself: + return + pull_request = data['pull_request'] + job_params = { + 'id': pull_request['id'], + 'label': pull_request['head']['label'], + 'branch': pull_request['head']['ref'], + 'sha': pull_request['head']['sha'], + 'clone_url': pull_request['head']['repo']['clone_url'], + 'repo_name': pull_request['head']['repo']['name'], + 'repo_api_url': data['repository']['url'], + 'repo_html_url': data['repository']['html_url'], + } + params = create_openqa_job_params(job_params) + job_url = openqa_schedule(params) + print(job_url) + gitea_post_status(job_params, job_url) + + +def gitea_post_status(job_params, job_url): + print("============== gitea_post_status") + sha = job_params['sha'] + statuses_url = job_params['repo_api_url'] + '/statuses/' + job_params['sha']; + token = os.environ.get("GITEA_TOKEN") + headers = {'User-Agent': USER_AGENT, 'Accept': 'application/json', 'Authorization': 'token ' + token} + payload = { + 'context': 'qam-openqa', + 'description': "openQA check", + 'state': "pending", + 'target_url': job_url, + } + request_post(statuses_url, headers, payload) + + +def request_post(url, headers, payload): + print("============== request_post") + print(payload) + try: + content = requests.post(url, headers=headers, data=payload) + content.raise_for_status() + except requests.exceptions.RequestException as e: + log.error("Error while fetching %s: %s" % (url, str(e))) + raise (e) + + +def create_openqa_job_params(job_params): + print("============== create_openqa_job_params") + raw_url = job_params['repo_html_url'] + '/raw/branch/' + job_params['sha']; + base_url = 'https://openqa.opensuse.org' + statuses_url = job_params['repo_api_url'] + '/statuses/' + job_params['sha']; + params = { + 'BUILD': job_params['repo_name'] + '#' + job_params['sha'], + 'CASEDIR': job_params['clone_url'] + '#' + job_params['sha'], + '_GROUP_ID': '0', + 'PRIO': '100', + 'NEEDLES_DIR': '%%CASEDIR%%/needles', + + # set the URL for the scenario definitions YAML file so the Minion job will download it from GitHub + 'SCENARIO_DEFINITIONS_YAML_FILE': raw_url + '/' + 'scenario-definitions.yaml', + + # add "target URL" for the "Details" button of the CI status + 'CI_TARGET_URL': raw_url, + + # set Gitea parameters so the Minion job will be able to report the status back to Gitea + 'GITEA_REPO': job_params['repo_name'], + 'GITEA_SHA': job_params['sha'], + 'GITEA_STATUSES_URL': statuses_url, + 'GITEA_PR_URL': job_params['repo_html_url'], + } + return params + + +def openqa_cli(subcommand, cmds, dry_run=False): + print("============== openqa_cli") + host = 'https://openqa.opensuse.org' + client_args = [ + "openqa-cli", + subcommand, + "--host", + host, + ] + cmds + log.debug("openqa_cli: %s %s" % (subcommand, client_args)) + res = subprocess.run( + (["echo", "Simulating: "] if dry_run else []) + client_args, + stdout=subprocess.PIPE, stderr=subprocess.PIPE + ) + if len(res.stderr): + log.warning(f"openqa_cli() {subcommand} stderr: {res.stderr}") + res.check_returncode() + return res.stdout.decode("utf-8"); + + +def openqa_schedule(params): + print("============== openqa_schedule") + scenario_url = 'https://raw.githubusercontent.com/os-autoinst/os-autoinst-distri-openQA/refs/heads/master/scenario-definitions.yaml' + scenario_yaml = fetch_url(scenario_url, request_type="text") + yaml_file = "/tmp/distri-openqa-scenario.yaml" + with open(yaml_file, 'w') as f: + f.write(scenario_yaml.decode("utf-8")) + args = [ + "--param-file", + "SCENARIO_DEFINITIONS_YAML=" + yaml_file, + "VERSION=Tumbleweed", + "DISTRI=openqa", + "FLAVOR=dev", + "ARCH=x86_64", + "HDD_1=opensuse-Tumbleweed-x86_64-20250920-minimalx@uefi.qcow2", + ] + for key in params: + args.append(key + '=' + params[key]) + output = openqa_cli('schedule', args, dry_run) + pattern = re.compile(r".*?(?Phttps?://\S+)", re.DOTALL) + search = pattern.match(output) + if search: + url = search.group("url") + else: + raise Exception('openqa-cli failed', 'Output did not contain a url. ' + output) + return url + + +def fetch_url(url, request_type="text"): + print("============== fetch_url") + try: + content = requests.get(url, headers={'User-Agent': USER_AGENT}) + content.raise_for_status() + except requests.exceptions.RequestException as e: + log.error("Error while fetching %s: %s" % (url, str(e))) + raise (e) + raw = content.content + if request_type == "json": + try: + content = content.json() + except json.decoder.JSONDecodeError as e: + log.error( + "Error while decoding JSON from %s -> >>%s<<: %s" + % (url, raw, str(e)) + ) + raise (e) + else: + content = raw + return content + + +if __name__ == "__main__": + args = parse_args() + if args.simulate_review_requested_event: + simulate(args) + else: + listen(args) diff --git a/tests/data/gitea-amqp/example-payload-gitea-review-requested.json b/tests/data/gitea-amqp/example-payload-gitea-review-requested.json new file mode 100644 index 00000000..7c0663f8 --- /dev/null +++ b/tests/data/gitea-amqp/example-payload-gitea-review-requested.json @@ -0,0 +1,437 @@ +{ + "action": "review_requested", + "number": 2, + "pull_request": { + "id": 1934, + "url": "https://src.opensuse.org/tinita/myplayground/pulls/2", + "number": 2, + "user": { + "id": 1373, + "login": "tinita", + "login_name": "52fc4206003375ffbf106c244c56c7222bd6f77496bf9d2bc424293f0e4d4c81", + "source_id": 9, + "full_name": "Tina Müller", + "email": "tina.mueller@suse.com", + "avatar_url": "https://src.opensuse.org/avatars/a7cbbf47205685e65899495b73778f47a153fc03b4efbdf2b30e1b11ae742112", + "html_url": "https://src.opensuse.org/tinita", + "language": "en-US", + "is_admin": false, + "last_login": "2025-08-27T22:36:13+02:00", + "created": "2025-02-26T22:33:36+01:00", + "restricted": false, + "active": true, + "prohibit_login": false, + "location": "", + "website": "", + "description": "", + "visibility": "public", + "followers_count": 0, + "following_count": 0, + "starred_repos_count": 1, + "username": "tinita" + }, + "title": "WIP just a test, ignore", + "body": "", + "labels": [], + "milestone": null, + "assignee": null, + "assignees": [], + "requested_reviewers": [ + { + "id": 1196, + "login": "mkittler", + "login_name": "", + "source_id": 0, + "full_name": "Marius Kittler", + "email": "mkittler@noreply.src.opensuse.org", + "avatar_url": "https://src.opensuse.org/avatar/68978c76d4e4d5476873c61cf7e8f2a1", + "html_url": "https://src.opensuse.org/mkittler", + "language": "", + "is_admin": false, + "last_login": "0001-01-01T00:00:00Z", + "created": "2024-10-18T14:19:24+02:00", + "restricted": false, + "active": false, + "prohibit_login": false, + "location": "", + "website": "", + "description": "", + "visibility": "public", + "followers_count": 0, + "following_count": 0, + "starred_repos_count": 0, + "username": "mkittler" + } + ], + "requested_reviewers_teams": [], + "state": "open", + "draft": false, + "is_locked": false, + "comments": 1, + "additions": 6, + "deletions": 0, + "changed_files": 1, + "html_url": "https://src.opensuse.org/tinita/myplayground/pulls/2", + "diff_url": "https://src.opensuse.org/tinita/myplayground/pulls/2.diff", + "patch_url": "https://src.opensuse.org/tinita/myplayground/pulls/2.patch", + "mergeable": true, + "merged": false, + "merged_at": null, + "merge_commit_sha": null, + "merged_by": null, + "allow_maintainer_edit": false, + "base": { + "label": "main", + "ref": "main", + "sha": "9bb6e3a0f89a3a3e48e50eb5120337384507b390059c344112016d654a17b54a", + "repo_id": 93650, + "repo": { + "id": 93650, + "owner": { + "id": 1373, + "login": "tinita", + "login_name": "", + "source_id": 0, + "full_name": "Tina Müller", + "email": "tinita@noreply.src.opensuse.org", + "avatar_url": "https://src.opensuse.org/avatars/a7cbbf47205685e65899495b73778f47a153fc03b4efbdf2b30e1b11ae742112", + "html_url": "https://src.opensuse.org/tinita", + "language": "", + "is_admin": false, + "last_login": "0001-01-01T00:00:00Z", + "created": "2025-02-26T22:33:36+01:00", + "restricted": false, + "active": false, + "prohibit_login": false, + "location": "", + "website": "", + "description": "", + "visibility": "public", + "followers_count": 0, + "following_count": 0, + "starred_repos_count": 1, + "username": "tinita" + }, + "name": "myplayground", + "full_name": "tinita/myplayground", + "description": "", + "empty": false, + "private": false, + "fork": false, + "template": false, + "mirror": false, + "size": 37, + "language": "", + "languages_url": "https://src.opensuse.org/api/v1/repos/tinita/myplayground/languages", + "html_url": "https://src.opensuse.org/tinita/myplayground", + "url": "https://src.opensuse.org/api/v1/repos/tinita/myplayground", + "link": "", + "ssh_url": "gitea@src.opensuse.org:tinita/myplayground.git", + "clone_url": "https://src.opensuse.org/tinita/myplayground.git", + "original_url": "", + "website": "", + "stars_count": 0, + "forks_count": 0, + "watchers_count": 1, + "open_issues_count": 1, + "open_pr_counter": 1, + "release_counter": 0, + "default_branch": "main", + "archived": false, + "created_at": "2025-03-05T14:05:15+01:00", + "updated_at": "2025-09-16T00:27:55+02:00", + "archived_at": "1970-01-01T01:00:00+01:00", + "permissions": { + "admin": true, + "push": true, + "pull": true + }, + "has_issues": true, + "internal_tracker": { + "enable_time_tracker": false, + "allow_only_contributors_to_track_time": true, + "enable_issue_dependencies": true + }, + "has_wiki": true, + "has_pull_requests": true, + "has_projects": true, + "projects_mode": "all", + "has_releases": true, + "has_packages": true, + "has_actions": true, + "ignore_whitespace_conflicts": false, + "allow_merge_commits": true, + "allow_rebase": true, + "allow_rebase_explicit": true, + "allow_squash_merge": true, + "allow_fast_forward_only_merge": true, + "allow_rebase_update": true, + "allow_manual_merge": false, + "autodetect_manual_merge": false, + "default_delete_branch_after_merge": false, + "default_merge_style": "merge", + "default_allow_maintainer_edit": false, + "avatar_url": "", + "internal": false, + "mirror_interval": "", + "object_format_name": "sha256", + "mirror_updated": "0001-01-01T00:00:00Z", + "topics": [], + "licenses": [] + } + }, + "head": { + "label": "testbranch", + "ref": "testbranch", + "sha": "ebe9d6a28e89632ce61cccacc196960a3543be17e4ec0ae86d54091f9a5574ae", + "repo_id": 93650, + "repo": { + "id": 93650, + "owner": { + "id": 1373, + "login": "tinita", + "login_name": "", + "source_id": 0, + "full_name": "Tina Müller", + "email": "tinita@noreply.src.opensuse.org", + "avatar_url": "https://src.opensuse.org/avatars/a7cbbf47205685e65899495b73778f47a153fc03b4efbdf2b30e1b11ae742112", + "html_url": "https://src.opensuse.org/tinita", + "language": "", + "is_admin": false, + "last_login": "0001-01-01T00:00:00Z", + "created": "2025-02-26T22:33:36+01:00", + "restricted": false, + "active": false, + "prohibit_login": false, + "location": "", + "website": "", + "description": "", + "visibility": "public", + "followers_count": 0, + "following_count": 0, + "starred_repos_count": 1, + "username": "tinita" + }, + "name": "myplayground", + "full_name": "tinita/myplayground", + "description": "", + "empty": false, + "private": false, + "fork": false, + "template": false, + "mirror": false, + "size": 37, + "language": "", + "languages_url": "https://src.opensuse.org/api/v1/repos/tinita/myplayground/languages", + "html_url": "https://src.opensuse.org/tinita/myplayground", + "url": "https://src.opensuse.org/api/v1/repos/tinita/myplayground", + "link": "", + "ssh_url": "gitea@src.opensuse.org:tinita/myplayground.git", + "clone_url": "https://src.opensuse.org/tinita/myplayground.git", + "original_url": "", + "website": "", + "stars_count": 0, + "forks_count": 0, + "watchers_count": 1, + "open_issues_count": 1, + "open_pr_counter": 1, + "release_counter": 0, + "default_branch": "main", + "archived": false, + "created_at": "2025-03-05T14:05:15+01:00", + "updated_at": "2025-09-16T00:27:55+02:00", + "archived_at": "1970-01-01T01:00:00+01:00", + "permissions": { + "admin": true, + "push": true, + "pull": true + }, + "has_issues": true, + "internal_tracker": { + "enable_time_tracker": false, + "allow_only_contributors_to_track_time": true, + "enable_issue_dependencies": true + }, + "has_wiki": true, + "has_pull_requests": true, + "has_projects": true, + "projects_mode": "all", + "has_releases": true, + "has_packages": true, + "has_actions": true, + "ignore_whitespace_conflicts": false, + "allow_merge_commits": true, + "allow_rebase": true, + "allow_rebase_explicit": true, + "allow_squash_merge": true, + "allow_fast_forward_only_merge": true, + "allow_rebase_update": true, + "allow_manual_merge": false, + "autodetect_manual_merge": false, + "default_delete_branch_after_merge": false, + "default_merge_style": "merge", + "default_allow_maintainer_edit": false, + "avatar_url": "", + "internal": false, + "mirror_interval": "", + "object_format_name": "sha256", + "mirror_updated": "0001-01-01T00:00:00Z", + "topics": [], + "licenses": [] + } + }, + "merge_base": "9bb6e3a0f89a3a3e48e50eb5120337384507b390059c344112016d654a17b54a", + "due_date": null, + "created_at": "2025-08-14T14:53:04+02:00", + "updated_at": "2025-09-23T16:59:20+02:00", + "closed_at": null, + "pin_order": 0 + }, + "requested_reviewer": { + "id": 1196, + "login": "mkittler", + "login_name": "", + "source_id": 0, + "full_name": "Marius Kittler", + "email": "mkittler@noreply.src.opensuse.org", + "avatar_url": "https://src.opensuse.org/avatar/68978c76d4e4d5476873c61cf7e8f2a1", + "html_url": "https://src.opensuse.org/mkittler", + "language": "", + "is_admin": false, + "last_login": "0001-01-01T00:00:00Z", + "created": "2024-10-18T14:19:24+02:00", + "restricted": false, + "active": false, + "prohibit_login": false, + "location": "", + "website": "", + "description": "", + "visibility": "public", + "followers_count": 0, + "following_count": 0, + "starred_repos_count": 0, + "username": "mkittler" + }, + "repository": { + "id": 93650, + "owner": { + "id": 1373, + "login": "tinita", + "login_name": "", + "source_id": 0, + "full_name": "Tina Müller", + "email": "tinita@noreply.src.opensuse.org", + "avatar_url": "https://src.opensuse.org/avatars/a7cbbf47205685e65899495b73778f47a153fc03b4efbdf2b30e1b11ae742112", + "html_url": "https://src.opensuse.org/tinita", + "language": "", + "is_admin": false, + "last_login": "0001-01-01T00:00:00Z", + "created": "2025-02-26T22:33:36+01:00", + "restricted": false, + "active": false, + "prohibit_login": false, + "location": "", + "website": "", + "description": "", + "visibility": "public", + "followers_count": 0, + "following_count": 0, + "starred_repos_count": 1, + "username": "tinita" + }, + "name": "myplayground", + "full_name": "tinita/myplayground", + "description": "", + "empty": false, + "private": false, + "fork": false, + "template": false, + "mirror": false, + "size": 37, + "language": "", + "languages_url": "https://src.opensuse.org/api/v1/repos/tinita/myplayground/languages", + "html_url": "https://src.opensuse.org/tinita/myplayground", + "url": "https://src.opensuse.org/api/v1/repos/tinita/myplayground", + "link": "", + "ssh_url": "gitea@src.opensuse.org:tinita/myplayground.git", + "clone_url": "https://src.opensuse.org/tinita/myplayground.git", + "original_url": "", + "website": "", + "stars_count": 0, + "forks_count": 0, + "watchers_count": 1, + "open_issues_count": 1, + "open_pr_counter": 1, + "release_counter": 0, + "default_branch": "main", + "archived": false, + "created_at": "2025-03-05T14:05:15+01:00", + "updated_at": "2025-09-16T00:27:55+02:00", + "archived_at": "1970-01-01T01:00:00+01:00", + "permissions": { + "admin": true, + "push": true, + "pull": true + }, + "has_issues": true, + "internal_tracker": { + "enable_time_tracker": false, + "allow_only_contributors_to_track_time": true, + "enable_issue_dependencies": true + }, + "has_wiki": true, + "has_pull_requests": true, + "has_projects": true, + "projects_mode": "all", + "has_releases": true, + "has_packages": true, + "has_actions": true, + "ignore_whitespace_conflicts": false, + "allow_merge_commits": true, + "allow_rebase": true, + "allow_rebase_explicit": true, + "allow_squash_merge": true, + "allow_fast_forward_only_merge": true, + "allow_rebase_update": true, + "allow_manual_merge": false, + "autodetect_manual_merge": false, + "default_delete_branch_after_merge": false, + "default_merge_style": "merge", + "default_allow_maintainer_edit": false, + "avatar_url": "", + "internal": false, + "mirror_interval": "", + "object_format_name": "sha256", + "mirror_updated": "0001-01-01T00:00:00Z", + "topics": [], + "licenses": [] + }, + "sender": { + "id": 1373, + "login": "tinita", + "login_name": "", + "source_id": 0, + "full_name": "Tina Müller", + "email": "tinita@noreply.src.opensuse.org", + "avatar_url": "https://src.opensuse.org/avatars/a7cbbf47205685e65899495b73778f47a153fc03b4efbdf2b30e1b11ae742112", + "html_url": "https://src.opensuse.org/tinita", + "language": "", + "is_admin": false, + "last_login": "0001-01-01T00:00:00Z", + "created": "2025-02-26T22:33:36+01:00", + "restricted": false, + "active": false, + "prohibit_login": false, + "location": "", + "website": "", + "description": "", + "visibility": "public", + "followers_count": 0, + "following_count": 0, + "starred_repos_count": 1, + "username": "tinita" + }, + "commit_id": "", + "review": null +} + diff --git a/tests/data/gitea-amqp/minimal-payload-gitea-review-requested.json b/tests/data/gitea-amqp/minimal-payload-gitea-review-requested.json new file mode 100644 index 00000000..b2c031e2 --- /dev/null +++ b/tests/data/gitea-amqp/minimal-payload-gitea-review-requested.json @@ -0,0 +1,26 @@ +{ + "action": "review_requested", + "pull_request": { + "id": 1234, + "url": "https://src.opensuse.org.de/api/v1/repos/owner/reponame/pulls/1234", + "html_url": "https://src.opensuse.org/owner/reponame/pulls/1234", + "state": "open", + "head": { + "label": "owner:testhook", + "ref": "testhook", + "sha": "04a3f669ea13a4aa7cbd4569f578a66f7403c43d", + "repo": { + "name": "reponame", + "full_name": "owner/reponame", + "clone_url": "https://src.opensuse.org/owner/reponame.git" + } + } + }, + "repository": { + "url": "https://src.opensuse.org/api/v1/repos/owner/reponame", + "html_url": "https://src.opensuse.org/owner/reponame" + }, + "requested_reviewer": { + "username": "qam-openqa" + } +} diff --git a/tests/test_amqp.py b/tests/test_amqp.py new file mode 100644 index 00000000..7aa50ec4 --- /dev/null +++ b/tests/test_amqp.py @@ -0,0 +1,164 @@ +import os.path +import importlib.machinery +from argparse import Namespace +from unittest.mock import MagicMock, call, patch + +rootpath = os.path.abspath(os.path.join(os.path.dirname(__file__), "..")) + +loader = importlib.machinery.SourceFileLoader( + "openqa", rootpath + "/amqp-listen-gitea.py" +) +spec = importlib.util.spec_from_loader(loader.name, loader) +openqa = importlib.util.module_from_spec(spec) +loader.exec_module(openqa) + +def args_factory(): + args = Namespace() + args.myself = 'qam-openqa' + args.verbose = 1 + return args + + +def mocked_create_openqa_job(job_params): + return { 'foo': 'bar' } + + +def mocked_openqa_schedule(params): + return 'https://openqa.opensuse.org/tests/123456' + + +def mocked_openqa_cli(subcommand, cmds, dry_run=False): + output = """ + {"count":6,"failed":[],"ids":[5335402,5335403,5335404,5335405,5335406,5335407],"scheduled_product_id":515537} + 6 jobs have been created: + - https://openqa.opensuse.org/tests/5335402 + - https://openqa.opensuse.org/tests/5335403 + - https://openqa.opensuse.org/tests/5335404 + - https://openqa.opensuse.org/tests/5335405 + - https://openqa.opensuse.org/tests/5335406 + - https://openqa.opensuse.org/tests/5335407 + """ + return output + + +def mocked_gitea_post_status(job_params, job_url): + pass + +def mocked_fetch_url(url, request_type="text"): + return b'' + + +def mocked_request_post(url, headers, payload): + pass + + +data = { + 'requested_reviewer': { 'username': 'qam-openqa' }, + 'pull_request': { + 'id': 23, + 'head': { + 'sha': 'c0ffee', + 'ref': 'branch', + 'label': 'pr_user:branch', + 'repo': { + 'clone_url': 'https://src.opensuse.org/owner/reponame.git', + 'name': 'reponame', + } + } + }, + 'repository': { + 'url': 'https://src.opensuse.org/api/v1/repos/owner/reponame', + 'html_url': 'https://src.opensuse.org/owner/reponame', + }, +} + +job_params = { + 'id': 23, + 'sha': 'c0ffee', + 'label': 'pr_user:branch', + 'clone_url': 'https://src.opensuse.org/owner/reponame.git', + 'branch': 'branch', + 'repo_name': 'reponame', + 'repo_api_url': 'https://src.opensuse.org/api/v1/repos/owner/reponame', + 'repo_html_url': 'https://src.opensuse.org/owner/reponame' +} + + +class TestAMQP: + + + def test_nothing_todo(mock_amqp): + args = args_factory() + data = { + 'requested_reviewer': { 'username': 'someone-else' } + } + openqa.handle_review_request(data, args) + #openqa.create_openqa_job_params.assert_not_called() + + + def test_schedule_job(mock_amqp): + openqa.openqa_cli = MagicMock(side_effect=mocked_openqa_cli) + openqa.fetch_url = MagicMock(side_effect=mocked_fetch_url) + job_url = openqa.openqa_schedule({'foo': 'bar'}) + args = [ + '--param-file', + 'SCENARIO_DEFINITIONS_YAML=/tmp/distri-openqa-scenario.yaml', + 'VERSION=Tumbleweed', + 'DISTRI=openqa', + 'FLAVOR=dev', + 'ARCH=x86_64', + 'HDD_1=opensuse-Tumbleweed-x86_64-20250920-minimalx@uefi.qcow2', + 'foo=bar', + ] + openqa.openqa_cli.assert_called_once_with('schedule', args, False) + print(job_url) + assert(job_url == 'https://openqa.opensuse.org/tests/5335402') + + + def test_gitea_post_status(mock_amqp): + openqa.request_post = MagicMock(side_effect=mocked_request_post) + os.environ["GITEA_TOKEN"] = "abcdef" + openqa.gitea_post_status(job_params, 'https://openqa.example') + openqa.request_post.assert_called_once_with( + 'https://src.opensuse.org/api/v1/repos/owner/reponame/statuses/c0ffee', + { + 'Accept': 'application/json', + 'Authorization': 'token abcdef', + 'User-Agent': 'amqp-listen-gitea.py (https://github.com/os-autoinst/scripts)', + }, + { + 'context': 'qam-openqa', + 'description': 'openQA check', + 'state': 'pending', + 'target_url': 'https://openqa.example', + } + ) + + def test_create_openqa_job_params(mock_amqp): + args = args_factory() + openqa.openqa_schedule = MagicMock(side_effect=mocked_openqa_schedule) + openqa.gitea_post_status = MagicMock(side_effect=mocked_gitea_post_status) + openqa.handle_review_request(data, args) + openqa.openqa_schedule.assert_called_once_with({ + 'BUILD': 'reponame#c0ffee', + 'CASEDIR': 'https://src.opensuse.org/owner/reponame.git#c0ffee', + '_GROUP_ID': '0', + 'PRIO': '100', + 'NEEDLES_DIR': '%%CASEDIR%%/needles', + 'SCENARIO_DEFINITIONS_YAML_FILE': 'https://src.opensuse.org/owner/reponame/raw/branch/c0ffee/scenario-definitions.yaml', + 'CI_TARGET_URL': 'https://src.opensuse.org/owner/reponame/raw/branch/c0ffee', + 'GITEA_REPO': 'reponame', + 'GITEA_SHA': 'c0ffee', + 'GITEA_STATUSES_URL': 'https://src.opensuse.org/api/v1/repos/owner/reponame/statuses/c0ffee', + 'GITEA_PR_URL': 'https://src.opensuse.org/owner/reponame', + }) + openqa.gitea_post_status.assert_called_once_with(job_params, 'https://openqa.opensuse.org/tests/123456') + + + def test_handle_review_request(mock_amqp): + args = args_factory() + openqa.create_openqa_job_params = MagicMock(side_effect=mocked_create_openqa_job) + openqa.handle_review_request(data, args) + openqa.create_openqa_job_params.assert_called_once_with(job_params) + + From 9b9139bc47f203801a4cac0daa88ef51783b090d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tina=20M=C3=BCller?= Date: Wed, 24 Sep 2025 18:19:42 +0200 Subject: [PATCH 02/14] Remove trailing spaces --- ...xample-payload-gitea-review-requested.json | 66 +++++++++---------- 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/tests/data/gitea-amqp/example-payload-gitea-review-requested.json b/tests/data/gitea-amqp/example-payload-gitea-review-requested.json index 7c0663f8..ad00a18a 100644 --- a/tests/data/gitea-amqp/example-payload-gitea-review-requested.json +++ b/tests/data/gitea-amqp/example-payload-gitea-review-requested.json @@ -1,40 +1,40 @@ -{ - "action": "review_requested", - "number": 2, - "pull_request": { - "id": 1934, +{ + "action": "review_requested", + "number": 2, + "pull_request": { + "id": 1934, "url": "https://src.opensuse.org/tinita/myplayground/pulls/2", - "number": 2, - "user": { - "id": 1373, - "login": "tinita", + "number": 2, + "user": { + "id": 1373, + "login": "tinita", "login_name": "52fc4206003375ffbf106c244c56c7222bd6f77496bf9d2bc424293f0e4d4c81", - "source_id": 9, + "source_id": 9, "full_name": "Tina Müller", "email": "tina.mueller@suse.com", "avatar_url": "https://src.opensuse.org/avatars/a7cbbf47205685e65899495b73778f47a153fc03b4efbdf2b30e1b11ae742112", - "html_url": "https://src.opensuse.org/tinita", - "language": "en-US", + "html_url": "https://src.opensuse.org/tinita", + "language": "en-US", "is_admin": false, "last_login": "2025-08-27T22:36:13+02:00", "created": "2025-02-26T22:33:36+01:00", - "restricted": false, - "active": true, - "prohibit_login": false, - "location": "", - "website": "", - "description": "", - "visibility": "public", - "followers_count": 0, - "following_count": 0, - "starred_repos_count": 1, - "username": "tinita" - }, + "restricted": false, + "active": true, + "prohibit_login": false, + "location": "", + "website": "", + "description": "", + "visibility": "public", + "followers_count": 0, + "following_count": 0, + "starred_repos_count": 1, + "username": "tinita" + }, "title": "WIP just a test, ignore", - "body": "", - "labels": [], - "milestone": null, - "assignee": null, + "body": "", + "labels": [], + "milestone": null, + "assignee": null, "assignees": [], "requested_reviewers": [ { @@ -45,7 +45,7 @@ "full_name": "Marius Kittler", "email": "mkittler@noreply.src.opensuse.org", "avatar_url": "https://src.opensuse.org/avatar/68978c76d4e4d5476873c61cf7e8f2a1", - "html_url": "https://src.opensuse.org/mkittler", + "html_url": "https://src.opensuse.org/mkittler", "language": "", "is_admin": false, "last_login": "0001-01-01T00:00:00Z", @@ -95,7 +95,7 @@ "full_name": "Tina Müller", "email": "tinita@noreply.src.opensuse.org", "avatar_url": "https://src.opensuse.org/avatars/a7cbbf47205685e65899495b73778f47a153fc03b4efbdf2b30e1b11ae742112", - "html_url": "https://src.opensuse.org/tinita", + "html_url": "https://src.opensuse.org/tinita", "language": "", "is_admin": false, "last_login": "0001-01-01T00:00:00Z", @@ -149,7 +149,7 @@ "has_issues": true, "internal_tracker": { "enable_time_tracker": false, - "allow_only_contributors_to_track_time": true, + "allow_only_contributors_to_track_time": true, "enable_issue_dependencies": true }, "has_wiki": true, @@ -195,7 +195,7 @@ "full_name": "Tina Müller", "email": "tinita@noreply.src.opensuse.org", "avatar_url": "https://src.opensuse.org/avatars/a7cbbf47205685e65899495b73778f47a153fc03b4efbdf2b30e1b11ae742112", - "html_url": "https://src.opensuse.org/tinita", + "html_url": "https://src.opensuse.org/tinita", "language": "", "is_admin": false, "last_login": "0001-01-01T00:00:00Z", @@ -249,7 +249,7 @@ "has_issues": true, "internal_tracker": { "enable_time_tracker": false, - "allow_only_contributors_to_track_time": true, + "allow_only_contributors_to_track_time": true, "enable_issue_dependencies": true }, "has_wiki": true, From f1e8478cdb3e8dae48aafa6bac6a004de252773b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tina=20M=C3=BCller?= Date: Wed, 24 Sep 2025 18:20:31 +0200 Subject: [PATCH 03/14] Add --openqa-host --- amqp-listen-gitea.py | 14 +++++++------- tests/test_amqp.py | 14 ++++++++------ 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/amqp-listen-gitea.py b/amqp-listen-gitea.py index 40a936f0..54a1222b 100644 --- a/amqp-listen-gitea.py +++ b/amqp-listen-gitea.py @@ -21,6 +21,7 @@ def parse_args(): parser.add_argument("--prefix", help="Event prefix to collect", default="opensuse.src.") parser.add_argument("--event-type", help="Event type to collect", default="pull_request_review_request.review_requested") parser.add_argument("--myself", help="Username of bot", default="qam-openqa") + parser.add_argument("--openqa-host", help="OpenQA instance url", default="http://localhost:9526") parser.add_argument("--verbose", help="Verbosity", default="1", type=int, choices=[0, 1, 2, 3]) parser.add_argument("--simulate-review-requested-event", help="Behave as if a pull_request_review_request.review_requested was received") args = parser.parse_args() @@ -89,7 +90,7 @@ def handle_review_request(data, args): 'repo_html_url': data['repository']['html_url'], } params = create_openqa_job_params(job_params) - job_url = openqa_schedule(params) + job_url = openqa_schedule(args, params) print(job_url) gitea_post_status(job_params, job_url) @@ -147,9 +148,8 @@ def create_openqa_job_params(job_params): return params -def openqa_cli(subcommand, cmds, dry_run=False): +def openqa_cli(host, subcommand, cmds, dry_run=False): print("============== openqa_cli") - host = 'https://openqa.opensuse.org' client_args = [ "openqa-cli", subcommand, @@ -167,14 +167,14 @@ def openqa_cli(subcommand, cmds, dry_run=False): return res.stdout.decode("utf-8"); -def openqa_schedule(params): +def openqa_schedule(args, params): print("============== openqa_schedule") scenario_url = 'https://raw.githubusercontent.com/os-autoinst/os-autoinst-distri-openQA/refs/heads/master/scenario-definitions.yaml' scenario_yaml = fetch_url(scenario_url, request_type="text") yaml_file = "/tmp/distri-openqa-scenario.yaml" with open(yaml_file, 'w') as f: f.write(scenario_yaml.decode("utf-8")) - args = [ + cmd_args = [ "--param-file", "SCENARIO_DEFINITIONS_YAML=" + yaml_file, "VERSION=Tumbleweed", @@ -184,8 +184,8 @@ def openqa_schedule(params): "HDD_1=opensuse-Tumbleweed-x86_64-20250920-minimalx@uefi.qcow2", ] for key in params: - args.append(key + '=' + params[key]) - output = openqa_cli('schedule', args, dry_run) + cmd_args.append(key + '=' + params[key]) + output = openqa_cli(args.openqa_host, 'schedule', cmd_args, dry_run) pattern = re.compile(r".*?(?Phttps?://\S+)", re.DOTALL) search = pattern.match(output) if search: diff --git a/tests/test_amqp.py b/tests/test_amqp.py index 7aa50ec4..2c723ce7 100644 --- a/tests/test_amqp.py +++ b/tests/test_amqp.py @@ -16,6 +16,7 @@ def args_factory(): args = Namespace() args.myself = 'qam-openqa' args.verbose = 1 + args.openqa_host = 'https://openqa.example' return args @@ -23,11 +24,11 @@ def mocked_create_openqa_job(job_params): return { 'foo': 'bar' } -def mocked_openqa_schedule(params): +def mocked_openqa_schedule(args, params): return 'https://openqa.opensuse.org/tests/123456' -def mocked_openqa_cli(subcommand, cmds, dry_run=False): +def mocked_openqa_cli(host, subcommand, cmds, dry_run=False): output = """ {"count":6,"failed":[],"ids":[5335402,5335403,5335404,5335405,5335406,5335407],"scheduled_product_id":515537} 6 jobs have been created: @@ -97,10 +98,11 @@ def test_nothing_todo(mock_amqp): def test_schedule_job(mock_amqp): + args = args_factory() openqa.openqa_cli = MagicMock(side_effect=mocked_openqa_cli) openqa.fetch_url = MagicMock(side_effect=mocked_fetch_url) - job_url = openqa.openqa_schedule({'foo': 'bar'}) - args = [ + job_url = openqa.openqa_schedule(args, {'foo': 'bar'}) + cmd_args = [ '--param-file', 'SCENARIO_DEFINITIONS_YAML=/tmp/distri-openqa-scenario.yaml', 'VERSION=Tumbleweed', @@ -110,7 +112,7 @@ def test_schedule_job(mock_amqp): 'HDD_1=opensuse-Tumbleweed-x86_64-20250920-minimalx@uefi.qcow2', 'foo=bar', ] - openqa.openqa_cli.assert_called_once_with('schedule', args, False) + openqa.openqa_cli.assert_called_once_with(args.openqa_host, 'schedule', cmd_args, False) print(job_url) assert(job_url == 'https://openqa.opensuse.org/tests/5335402') @@ -139,7 +141,7 @@ def test_create_openqa_job_params(mock_amqp): openqa.openqa_schedule = MagicMock(side_effect=mocked_openqa_schedule) openqa.gitea_post_status = MagicMock(side_effect=mocked_gitea_post_status) openqa.handle_review_request(data, args) - openqa.openqa_schedule.assert_called_once_with({ + openqa.openqa_schedule.assert_called_once_with(args, { 'BUILD': 'reponame#c0ffee', 'CASEDIR': 'https://src.opensuse.org/owner/reponame.git#c0ffee', '_GROUP_ID': '0', From 65328e9a9035efc5bff77577ced137083ba18c2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tina=20M=C3=BCller?= Date: Wed, 24 Sep 2025 18:45:06 +0200 Subject: [PATCH 04/14] Add webhook_id to isos post call --- amqp-listen-gitea.py | 1 + tests/test_amqp.py | 8 +++++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/amqp-listen-gitea.py b/amqp-listen-gitea.py index 54a1222b..05406c30 100644 --- a/amqp-listen-gitea.py +++ b/amqp-listen-gitea.py @@ -144,6 +144,7 @@ def create_openqa_job_params(job_params): 'GITEA_SHA': job_params['sha'], 'GITEA_STATUSES_URL': statuses_url, 'GITEA_PR_URL': job_params['repo_html_url'], + 'webhook_id': 'gitea-soo:pr:' + job_params['id'], } return params diff --git a/tests/test_amqp.py b/tests/test_amqp.py index 2c723ce7..d9d6134f 100644 --- a/tests/test_amqp.py +++ b/tests/test_amqp.py @@ -56,7 +56,7 @@ def mocked_request_post(url, headers, payload): data = { 'requested_reviewer': { 'username': 'qam-openqa' }, 'pull_request': { - 'id': 23, + 'id': '23', 'head': { 'sha': 'c0ffee', 'ref': 'branch', @@ -74,7 +74,7 @@ def mocked_request_post(url, headers, payload): } job_params = { - 'id': 23, + 'id': '23', 'sha': 'c0ffee', 'label': 'pr_user:branch', 'clone_url': 'https://src.opensuse.org/owner/reponame.git', @@ -101,7 +101,7 @@ def test_schedule_job(mock_amqp): args = args_factory() openqa.openqa_cli = MagicMock(side_effect=mocked_openqa_cli) openqa.fetch_url = MagicMock(side_effect=mocked_fetch_url) - job_url = openqa.openqa_schedule(args, {'foo': 'bar'}) + job_url = openqa.openqa_schedule(args, {'webhook_id': 'gitea-soo:pr:42', 'foo': 'bar'}) cmd_args = [ '--param-file', 'SCENARIO_DEFINITIONS_YAML=/tmp/distri-openqa-scenario.yaml', @@ -110,6 +110,7 @@ def test_schedule_job(mock_amqp): 'FLAVOR=dev', 'ARCH=x86_64', 'HDD_1=opensuse-Tumbleweed-x86_64-20250920-minimalx@uefi.qcow2', + 'webhook_id=gitea-soo:pr:42', 'foo=bar', ] openqa.openqa_cli.assert_called_once_with(args.openqa_host, 'schedule', cmd_args, False) @@ -153,6 +154,7 @@ def test_create_openqa_job_params(mock_amqp): 'GITEA_SHA': 'c0ffee', 'GITEA_STATUSES_URL': 'https://src.opensuse.org/api/v1/repos/owner/reponame/statuses/c0ffee', 'GITEA_PR_URL': 'https://src.opensuse.org/owner/reponame', + 'webhook_id': 'gitea-soo:pr:23', }) openqa.gitea_post_status.assert_called_once_with(job_params, 'https://openqa.opensuse.org/tests/123456') From 1f4e9ef0e4b62fe317f8733de5205ec0057e8687 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tina=20M=C3=BCller?= Date: Thu, 25 Sep 2025 14:31:43 +0200 Subject: [PATCH 05/14] Fix GITEA_PR_URL to point to PR --- amqp-listen-gitea.py | 3 ++- tests/test_amqp.py | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/amqp-listen-gitea.py b/amqp-listen-gitea.py index 05406c30..3b05c270 100644 --- a/amqp-listen-gitea.py +++ b/amqp-listen-gitea.py @@ -84,6 +84,7 @@ def handle_review_request(data, args): 'label': pull_request['head']['label'], 'branch': pull_request['head']['ref'], 'sha': pull_request['head']['sha'], + 'pr_html_url': pull_request['html_url'], 'clone_url': pull_request['head']['repo']['clone_url'], 'repo_name': pull_request['head']['repo']['name'], 'repo_api_url': data['repository']['url'], @@ -143,7 +144,7 @@ def create_openqa_job_params(job_params): 'GITEA_REPO': job_params['repo_name'], 'GITEA_SHA': job_params['sha'], 'GITEA_STATUSES_URL': statuses_url, - 'GITEA_PR_URL': job_params['repo_html_url'], + 'GITEA_PR_URL': job_params['pr_html_url'], 'webhook_id': 'gitea-soo:pr:' + job_params['id'], } return params diff --git a/tests/test_amqp.py b/tests/test_amqp.py index d9d6134f..afccf66e 100644 --- a/tests/test_amqp.py +++ b/tests/test_amqp.py @@ -57,6 +57,7 @@ def mocked_request_post(url, headers, payload): 'requested_reviewer': { 'username': 'qam-openqa' }, 'pull_request': { 'id': '23', + 'html_url': 'https://src.opensuse.org/owner/reponame/pulls/1234', 'head': { 'sha': 'c0ffee', 'ref': 'branch', @@ -79,6 +80,7 @@ def mocked_request_post(url, headers, payload): 'label': 'pr_user:branch', 'clone_url': 'https://src.opensuse.org/owner/reponame.git', 'branch': 'branch', + 'pr_html_url': 'https://src.opensuse.org/owner/reponame/pulls/1234', 'repo_name': 'reponame', 'repo_api_url': 'https://src.opensuse.org/api/v1/repos/owner/reponame', 'repo_html_url': 'https://src.opensuse.org/owner/reponame' @@ -153,7 +155,7 @@ def test_create_openqa_job_params(mock_amqp): 'GITEA_REPO': 'reponame', 'GITEA_SHA': 'c0ffee', 'GITEA_STATUSES_URL': 'https://src.opensuse.org/api/v1/repos/owner/reponame/statuses/c0ffee', - 'GITEA_PR_URL': 'https://src.opensuse.org/owner/reponame', + 'GITEA_PR_URL': 'https://src.opensuse.org/owner/reponame/pulls/1234', 'webhook_id': 'gitea-soo:pr:23', }) openqa.gitea_post_status.assert_called_once_with(job_params, 'https://openqa.opensuse.org/tests/123456') From 654d604d0c1a89706a1fd059ce6d67f24d1bbebe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tina=20M=C3=BCller?= Date: Fri, 26 Sep 2025 23:28:13 +0200 Subject: [PATCH 06/14] Fix CI_TARGET_URL --- amqp-listen-gitea.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/amqp-listen-gitea.py b/amqp-listen-gitea.py index 3b05c270..ff1f9d30 100644 --- a/amqp-listen-gitea.py +++ b/amqp-listen-gitea.py @@ -138,14 +138,14 @@ def create_openqa_job_params(job_params): 'SCENARIO_DEFINITIONS_YAML_FILE': raw_url + '/' + 'scenario-definitions.yaml', # add "target URL" for the "Details" button of the CI status - 'CI_TARGET_URL': raw_url, + 'CI_TARGET_URL': base_url, # set Gitea parameters so the Minion job will be able to report the status back to Gitea 'GITEA_REPO': job_params['repo_name'], 'GITEA_SHA': job_params['sha'], 'GITEA_STATUSES_URL': statuses_url, 'GITEA_PR_URL': job_params['pr_html_url'], - 'webhook_id': 'gitea-soo:pr:' + job_params['id'], + 'webhook_id': 'gitea:pr:' + str(job_params['id']), } return params From 732cd2e12055ee81badd32056a274f88ca4c8415 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tina=20M=C3=BCller?= Date: Fri, 26 Sep 2025 23:44:04 +0200 Subject: [PATCH 07/14] WIP --- amqp-listen-gitea.py | 7 +++---- tests/test_amqp.py | 12 ++++++------ 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/amqp-listen-gitea.py b/amqp-listen-gitea.py index ff1f9d30..e28f7536 100644 --- a/amqp-listen-gitea.py +++ b/amqp-listen-gitea.py @@ -90,7 +90,7 @@ def handle_review_request(data, args): 'repo_api_url': data['repository']['url'], 'repo_html_url': data['repository']['html_url'], } - params = create_openqa_job_params(job_params) + params = create_openqa_job_params(args, job_params) job_url = openqa_schedule(args, params) print(job_url) gitea_post_status(job_params, job_url) @@ -122,10 +122,9 @@ def request_post(url, headers, payload): raise (e) -def create_openqa_job_params(job_params): +def create_openqa_job_params(args, job_params): print("============== create_openqa_job_params") raw_url = job_params['repo_html_url'] + '/raw/branch/' + job_params['sha']; - base_url = 'https://openqa.opensuse.org' statuses_url = job_params['repo_api_url'] + '/statuses/' + job_params['sha']; params = { 'BUILD': job_params['repo_name'] + '#' + job_params['sha'], @@ -138,7 +137,7 @@ def create_openqa_job_params(job_params): 'SCENARIO_DEFINITIONS_YAML_FILE': raw_url + '/' + 'scenario-definitions.yaml', # add "target URL" for the "Details" button of the CI status - 'CI_TARGET_URL': base_url, + 'CI_TARGET_URL': args.openqa_host, # set Gitea parameters so the Minion job will be able to report the status back to Gitea 'GITEA_REPO': job_params['repo_name'], diff --git a/tests/test_amqp.py b/tests/test_amqp.py index afccf66e..3505e082 100644 --- a/tests/test_amqp.py +++ b/tests/test_amqp.py @@ -20,7 +20,7 @@ def args_factory(): return args -def mocked_create_openqa_job(job_params): +def mocked_create_openqa_job(args, job_params): return { 'foo': 'bar' } @@ -103,7 +103,7 @@ def test_schedule_job(mock_amqp): args = args_factory() openqa.openqa_cli = MagicMock(side_effect=mocked_openqa_cli) openqa.fetch_url = MagicMock(side_effect=mocked_fetch_url) - job_url = openqa.openqa_schedule(args, {'webhook_id': 'gitea-soo:pr:42', 'foo': 'bar'}) + job_url = openqa.openqa_schedule(args, {'webhook_id': 'gitea:pr:42', 'foo': 'bar'}) cmd_args = [ '--param-file', 'SCENARIO_DEFINITIONS_YAML=/tmp/distri-openqa-scenario.yaml', @@ -112,7 +112,7 @@ def test_schedule_job(mock_amqp): 'FLAVOR=dev', 'ARCH=x86_64', 'HDD_1=opensuse-Tumbleweed-x86_64-20250920-minimalx@uefi.qcow2', - 'webhook_id=gitea-soo:pr:42', + 'webhook_id=gitea:pr:42', 'foo=bar', ] openqa.openqa_cli.assert_called_once_with(args.openqa_host, 'schedule', cmd_args, False) @@ -151,12 +151,12 @@ def test_create_openqa_job_params(mock_amqp): 'PRIO': '100', 'NEEDLES_DIR': '%%CASEDIR%%/needles', 'SCENARIO_DEFINITIONS_YAML_FILE': 'https://src.opensuse.org/owner/reponame/raw/branch/c0ffee/scenario-definitions.yaml', - 'CI_TARGET_URL': 'https://src.opensuse.org/owner/reponame/raw/branch/c0ffee', + 'CI_TARGET_URL': 'https://openqa.example', 'GITEA_REPO': 'reponame', 'GITEA_SHA': 'c0ffee', 'GITEA_STATUSES_URL': 'https://src.opensuse.org/api/v1/repos/owner/reponame/statuses/c0ffee', 'GITEA_PR_URL': 'https://src.opensuse.org/owner/reponame/pulls/1234', - 'webhook_id': 'gitea-soo:pr:23', + 'webhook_id': 'gitea:pr:23', }) openqa.gitea_post_status.assert_called_once_with(job_params, 'https://openqa.opensuse.org/tests/123456') @@ -165,6 +165,6 @@ def test_handle_review_request(mock_amqp): args = args_factory() openqa.create_openqa_job_params = MagicMock(side_effect=mocked_create_openqa_job) openqa.handle_review_request(data, args) - openqa.create_openqa_job_params.assert_called_once_with(job_params) + openqa.create_openqa_job_params.assert_called_once_with(args, job_params) From 79de72d8c4732980e5bc25760a8b41b5caea8dda Mon Sep 17 00:00:00 2001 From: Santiago Zarate Date: Thu, 2 Oct 2025 17:55:06 +0200 Subject: [PATCH 08/14] Allow storing events --- amqp-listen-gitea.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/amqp-listen-gitea.py b/amqp-listen-gitea.py index e28f7536..bef66879 100644 --- a/amqp-listen-gitea.py +++ b/amqp-listen-gitea.py @@ -8,6 +8,7 @@ import requests import re import logging +import datetime USER_AGENT = 'amqp-listen-gitea.py (https://github.com/os-autoinst/scripts)' dry_run=False @@ -24,6 +25,7 @@ def parse_args(): parser.add_argument("--openqa-host", help="OpenQA instance url", default="http://localhost:9526") parser.add_argument("--verbose", help="Verbosity", default="1", type=int, choices=[0, 1, 2, 3]) parser.add_argument("--simulate-review-requested-event", help="Behave as if a pull_request_review_request.review_requested was received") + parser.add_argument("--store-amqp", help="Should the amqp event be stored", action='store_true', default=False) args = parser.parse_args() return args @@ -57,6 +59,19 @@ def callback(ch, method, properties, body, args): if args.verbose >= 2: print(" [x] %r" % (method.routing_key)) data = json.loads(body) + + if args.store_amqp: + if data['requested_reviewer']['username'] == args.myself: + timestamp = datetime.datetime.now().strftime("%Y%m%d-%H%M%S") + filename = f"tests/data/gitea-amqp/amqp-{args.myself}-review-requested-{timestamp}.json" + try: + with open(filename, 'w') as file_object: + json.dump(data, file_object,indent=4) + log.info(f"Storing review-requested file to {filename}") + + except IOError as e: + log.error(f"Error saving file: {e}") + handle_review_request(data, args) From 8f4f9f751202bdc2b31b5c4b3ad7ce6544daca3f Mon Sep 17 00:00:00 2001 From: Santiago Zarate Date: Thu, 2 Oct 2025 18:29:14 +0200 Subject: [PATCH 09/14] Set correct url for build overview page in openQA --- amqp-listen-gitea.py | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/amqp-listen-gitea.py b/amqp-listen-gitea.py index bef66879..7138e18b 100644 --- a/amqp-listen-gitea.py +++ b/amqp-listen-gitea.py @@ -9,6 +9,7 @@ import re import logging import datetime +from urllib.parse import urlencode, urlunparse, urlparse USER_AGENT = 'amqp-listen-gitea.py (https://github.com/os-autoinst/scripts)' dry_run=False @@ -203,13 +204,17 @@ def openqa_schedule(args, params): cmd_args.append(key + '=' + params[key]) output = openqa_cli(args.openqa_host, 'schedule', cmd_args, dry_run) pattern = re.compile(r".*?(?Phttps?://\S+)", re.DOTALL) - search = pattern.match(output) - if search: - url = search.group("url") - else: - raise Exception('openqa-cli failed', 'Output did not contain a url. ' + output) - return url + query_parameters = { + "build": params["BUILD"], + "distri":"openqa", + "version":"Tumbleweed" + } + + base_url = urlparse(args.openqa_host+"/tests/overview") + query_string = urlencode(query_parameters) + test_overview_url = urlunparse(base_url._replace(query=query_string)) + return test_overview_url def fetch_url(url, request_type="text"): print("============== fetch_url") From 826edf1e2559fbe5740251bde44290d8ac3e0d38 Mon Sep 17 00:00:00 2001 From: Santiago Zarate Date: Mon, 6 Oct 2025 17:19:43 +0200 Subject: [PATCH 10/14] Handle review approved events by a known bot --- amqp-listen-gitea.py | 46 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/amqp-listen-gitea.py b/amqp-listen-gitea.py index 7138e18b..7432c468 100644 --- a/amqp-listen-gitea.py +++ b/amqp-listen-gitea.py @@ -26,6 +26,8 @@ def parse_args(): parser.add_argument("--openqa-host", help="OpenQA instance url", default="http://localhost:9526") parser.add_argument("--verbose", help="Verbosity", default="1", type=int, choices=[0, 1, 2, 3]) parser.add_argument("--simulate-review-requested-event", help="Behave as if a pull_request_review_request.review_requested was received") + parser.add_argument("--simulate-build-finished-event", help="Behave as if build is marked as finished") + parser.add_argument("--build-bot", help="Username of bot that approves when build is finished") parser.add_argument("--store-amqp", help="Should the amqp event be stored", action='store_true', default=False) args = parser.parse_args() return args @@ -83,6 +85,16 @@ def simulate(args): with open(json_file, 'r') as f: content = f.read() data = json.loads(content) + + if args.simulate_build_finished_event and args.build_bot: + print("build_finished_event properly initialized") + + json_file = args.simulate_build_finished_event + with open(json_file, 'r') as f: + content = f.read() + build_data = json.loads(content) + return handle_build_finished(build_data, args) + handle_review_request(data, args) @@ -111,6 +123,40 @@ def handle_review_request(data, args): print(job_url) gitea_post_status(job_params, job_url) +def handle_build_finished(data, args): + print("============== handle_build_finished") + build_bot = args.build_bot + myself = args.myself + if build_bot == data["sender"]["username"]: + print(f"Build marked as finished by ({build_bot})") + else: + if args.verbose >= 1: + print(f"Aborting: PR approval is by {data["sender"]["username"]}, not by our bot {build_bot}") + return + + pull_request = data['pull_request'] + job_params = { + 'id': pull_request['id'], + 'label': pull_request['head']['label'], + 'branch': pull_request['head']['ref'], + 'sha': pull_request['head']['sha'], + 'pr_html_url': pull_request['html_url'], + 'clone_url': pull_request['head']['repo']['clone_url'], + 'repo_name': pull_request['head']['repo']['name'], # this should be full_name but openQA cli complains + 'repo_api_url': data['repository']['url'], + 'repo_html_url': data['repository']['html_url'], + } + packages_in_testing = get_packages_from_obs_project(job_params) + job_params["packages"] = packages_in_testing + params = create_openqa_job_params(args, job_params) + job_url = openqa_schedule(args, params) + print(job_url) + gitea_post_status(job_params, job_url) + +def get_packages_from_obs_project(job_params): + # This should be able to query the OBS project to get the list of packages + # per Pull request + pass def gitea_post_status(job_params, job_url): print("============== gitea_post_status") From 7f36f3ada6b16f01dcfa2b4b5020be00591d069f Mon Sep 17 00:00:00 2001 From: Santiago Zarate Date: Mon, 6 Oct 2025 17:20:51 +0200 Subject: [PATCH 11/14] Change the event store logic to a more generic one --- amqp-listen-gitea.py | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/amqp-listen-gitea.py b/amqp-listen-gitea.py index 7432c468..701411e1 100644 --- a/amqp-listen-gitea.py +++ b/amqp-listen-gitea.py @@ -64,16 +64,17 @@ def callback(ch, method, properties, body, args): data = json.loads(body) if args.store_amqp: - if data['requested_reviewer']['username'] == args.myself: - timestamp = datetime.datetime.now().strftime("%Y%m%d-%H%M%S") - filename = f"tests/data/gitea-amqp/amqp-{args.myself}-review-requested-{timestamp}.json" - try: - with open(filename, 'w') as file_object: - json.dump(data, file_object,indent=4) - log.info(f"Storing review-requested file to {filename}") - - except IOError as e: - log.error(f"Error saving file: {e}") + timestamp = datetime.datetime.now().strftime("%Y%m%d-%H%M%S") + filename = f"tests/data/gitea-amqp/amqp-{args.myself}-{args.event_type}-{timestamp}.json" + try: + with open(filename, 'w') as file_object: + json.dump(data, file_object,indent=4) + log.info(f"Storing review-requested file to {filename}") + print(f"{args.event_type} captured, saved to {filename}. Exiting") + exit() + + except IOError as e: + log.error(f"Error saving file: {e}") handle_review_request(data, args) From 7fba329e5a00a8de2d623f07ab228b76ae1093a3 Mon Sep 17 00:00:00 2001 From: Santiago Zarate Date: Tue, 7 Oct 2025 09:58:37 +0200 Subject: [PATCH 12/14] Add filter by project and branch --- amqp-listen-gitea.py | 45 ++++++++++++++++++++++++++------------------ 1 file changed, 27 insertions(+), 18 deletions(-) diff --git a/amqp-listen-gitea.py b/amqp-listen-gitea.py index 701411e1..5908e65f 100644 --- a/amqp-listen-gitea.py +++ b/amqp-listen-gitea.py @@ -28,6 +28,8 @@ def parse_args(): parser.add_argument("--simulate-review-requested-event", help="Behave as if a pull_request_review_request.review_requested was received") parser.add_argument("--simulate-build-finished-event", help="Behave as if build is marked as finished") parser.add_argument("--build-bot", help="Username of bot that approves when build is finished") + parser.add_argument("--branch", help="Target branch, eg. leap 16.0") + parser.add_argument("--project", help="Target project") parser.add_argument("--store-amqp", help="Should the amqp event be stored", action='store_true', default=False) args = parser.parse_args() return args @@ -135,24 +137,31 @@ def handle_build_finished(data, args): print(f"Aborting: PR approval is by {data["sender"]["username"]}, not by our bot {build_bot}") return - pull_request = data['pull_request'] - job_params = { - 'id': pull_request['id'], - 'label': pull_request['head']['label'], - 'branch': pull_request['head']['ref'], - 'sha': pull_request['head']['sha'], - 'pr_html_url': pull_request['html_url'], - 'clone_url': pull_request['head']['repo']['clone_url'], - 'repo_name': pull_request['head']['repo']['name'], # this should be full_name but openQA cli complains - 'repo_api_url': data['repository']['url'], - 'repo_html_url': data['repository']['html_url'], - } - packages_in_testing = get_packages_from_obs_project(job_params) - job_params["packages"] = packages_in_testing - params = create_openqa_job_params(args, job_params) - job_url = openqa_schedule(args, params) - print(job_url) - gitea_post_status(job_params, job_url) + if (data["pull_request"]["base"]["label"] == args.branch and data["pull_request"]["base"]["repo"]["full_name"] == args.project): + + pull_request = data['pull_request'] + job_params = { + 'id': pull_request['id'], + 'label': pull_request['head']['label'], + 'branch': pull_request['head']['ref'], + 'sha': pull_request['head']['sha'], + 'pr_html_url': pull_request['html_url'], + 'clone_url': pull_request['head']['repo']['clone_url'], + 'repo_name': pull_request['head']['repo']['name'], # this should be full_name but openQA cli complains + 'repo_api_url': data['repository']['url'], + 'repo_html_url': data['repository']['html_url'], + } + packages_in_testing = get_packages_from_obs_project(job_params) + job_params["packages"] = packages_in_testing + params = create_openqa_job_params(args, job_params) + job_url = openqa_schedule(args, params) + print(job_url) + gitea_post_status(job_params, job_url) + + else: + if args.verbose >= 1: + print(f"Project and branch don't match {args.project}#{args.branch}") + return def get_packages_from_obs_project(job_params): # This should be able to query the OBS project to get the list of packages From b498bb9506c87b2e14672b58c9c71a3cf6b1c07e Mon Sep 17 00:00:00 2001 From: Santiago Zarate Date: Tue, 7 Oct 2025 09:59:27 +0200 Subject: [PATCH 13/14] Add data from pull request approval by autogits_workflow_pr_bot --- ...quest_review_approved-20251006-154156.json | 465 ++++++++++++++++++ 1 file changed, 465 insertions(+) create mode 100644 tests/data/gitea-amqp/amqp-autogits_workflow_pr_bot-pull_request_review_approved-20251006-154156.json diff --git a/tests/data/gitea-amqp/amqp-autogits_workflow_pr_bot-pull_request_review_approved-20251006-154156.json b/tests/data/gitea-amqp/amqp-autogits_workflow_pr_bot-pull_request_review_approved-20251006-154156.json new file mode 100644 index 00000000..c6b87be9 --- /dev/null +++ b/tests/data/gitea-amqp/amqp-autogits_workflow_pr_bot-pull_request_review_approved-20251006-154156.json @@ -0,0 +1,465 @@ +{ + "action": "reviewed", + "number": 160, + "pull_request": { + "id": 2932, + "url": "https://src.opensuse.org/products/PackageHub/pulls/160", + "number": 160, + "user": { + "id": 1652, + "login": "autogits_workflow_pr_bot", + "login_name": "", + "source_id": 0, + "full_name": "", + "email": "autogits_workflow_pr_bot@noreply.src.opensuse.org", + "avatar_url": "https://src.opensuse.org/avatar/dabd7e8102cdc7b31f1fa67c4bcb3908", + "html_url": "https://src.opensuse.org/autogits_workflow_pr_bot", + "language": "", + "is_admin": false, + "last_login": "0001-01-01T00:00:00Z", + "created": "2025-08-13T08:32:42+02:00", + "restricted": false, + "active": false, + "prohibit_login": false, + "location": "", + "website": "", + "description": "", + "visibility": "public", + "followers_count": 0, + "following_count": 0, + "starred_repos_count": 0, + "username": "autogits_workflow_pr_bot" + }, + "title": "Forwarded PRs: openQA", + "body": "This is a forwarded pull request by AutoGits PR Review Bot\nreferencing the following pull request(s):\n\nPR: pool/openQA!11\n\n### ManualMergeProject enabled. To merge, 'merge ok' is required by project maintainer in the project PR.", + "labels": [], + "milestone": null, + "assignee": null, + "assignees": [], + "requested_reviewers": [ + { + "id": 1778, + "login": "packagehub-review", + "login_name": "", + "source_id": 0, + "full_name": "", + "email": "packagehub-review@noreply.src.opensuse.org", + "avatar_url": "https://src.opensuse.org/avatar/484734e0814fd8726512df9f3b5b4373", + "html_url": "https://src.opensuse.org/packagehub-review", + "language": "", + "is_admin": false, + "last_login": "0001-01-01T00:00:00Z", + "created": "2025-09-26T15:25:43+02:00", + "restricted": false, + "active": false, + "prohibit_login": false, + "location": "", + "website": "", + "description": "", + "visibility": "public", + "followers_count": 0, + "following_count": 0, + "starred_repos_count": 0, + "username": "packagehub-review" + }, + { + "id": 1008, + "login": "autogits_obs_staging_bot", + "login_name": "", + "source_id": 0, + "full_name": "", + "email": "autogits_obs_staging_bot@noreply.src.opensuse.org", + "avatar_url": "https://src.opensuse.org/avatars/9aa9b21c0beaf80d4af7a0fca8a326862127f8b5fa68e47d0870800441ced967", + "html_url": "https://src.opensuse.org/autogits_obs_staging_bot", + "language": "", + "is_admin": false, + "last_login": "0001-01-01T00:00:00Z", + "created": "2024-07-06T14:31:34+02:00", + "restricted": false, + "active": false, + "prohibit_login": false, + "location": "", + "website": "", + "description": "I stage proposed changes and see if they build.", + "visibility": "public", + "followers_count": 0, + "following_count": 0, + "starred_repos_count": 0, + "username": "autogits_obs_staging_bot" + } + ], + "requested_reviewers_teams": [], + "state": "open", + "draft": false, + "is_locked": false, + "comments": 3, + "review_comments": 1, + "additions": 1, + "deletions": 1, + "changed_files": 1, + "html_url": "https://src.opensuse.org/products/PackageHub/pulls/160", + "diff_url": "https://src.opensuse.org/products/PackageHub/pulls/160.diff", + "patch_url": "https://src.opensuse.org/products/PackageHub/pulls/160.patch", + "mergeable": true, + "merged": false, + "merged_at": null, + "merge_commit_sha": null, + "merged_by": null, + "allow_maintainer_edit": false, + "base": { + "label": "leap-16.0", + "ref": "leap-16.0", + "sha": "61505d870aa91436971e71508c07500633ed485dc1d1417ac968a85f1d9511c8", + "repo_id": 91295, + "repo": { + "id": 91295, + "owner": { + "id": 181, + "login": "products", + "login_name": "", + "source_id": 0, + "full_name": "", + "email": "", + "avatar_url": "https://src.opensuse.org/avatars/86024cad1e83101d97359d7351051156", + "html_url": "https://src.opensuse.org/products", + "language": "", + "is_admin": false, + "last_login": "0001-01-01T00:00:00Z", + "created": "2023-09-20T11:20:19+02:00", + "restricted": false, + "active": false, + "prohibit_login": false, + "location": "", + "website": "", + "description": "", + "visibility": "public", + "followers_count": 0, + "following_count": 0, + "starred_repos_count": 0, + "username": "products" + }, + "name": "PackageHub", + "full_name": "products/PackageHub", + "description": "", + "empty": false, + "private": false, + "fork": false, + "template": false, + "mirror": false, + "size": 9297, + "language": "", + "languages_url": "https://src.opensuse.org/api/v1/repos/products/PackageHub/languages", + "html_url": "https://src.opensuse.org/products/PackageHub", + "url": "https://src.opensuse.org/api/v1/repos/products/PackageHub", + "link": "", + "ssh_url": "gitea@src.opensuse.org:products/PackageHub.git", + "clone_url": "https://src.opensuse.org/products/PackageHub.git", + "original_url": "", + "website": "", + "stars_count": 1, + "forks_count": 8, + "watchers_count": 14, + "open_issues_count": 0, + "open_pr_counter": 13, + "release_counter": 0, + "default_branch": "leap-16.0", + "archived": false, + "created_at": "2024-09-17T14:31:57+02:00", + "updated_at": "2025-10-06T15:24:40+02:00", + "archived_at": "1970-01-01T01:00:00+01:00", + "permissions": { + "admin": false, + "push": true, + "pull": true + }, + "has_issues": true, + "internal_tracker": { + "enable_time_tracker": false, + "allow_only_contributors_to_track_time": true, + "enable_issue_dependencies": true + }, + "has_wiki": false, + "has_pull_requests": true, + "has_projects": false, + "projects_mode": "all", + "has_releases": false, + "has_packages": false, + "has_actions": true, + "ignore_whitespace_conflicts": false, + "allow_merge_commits": true, + "allow_rebase": true, + "allow_rebase_explicit": true, + "allow_squash_merge": true, + "allow_fast_forward_only_merge": true, + "allow_rebase_update": true, + "allow_manual_merge": true, + "autodetect_manual_merge": true, + "default_delete_branch_after_merge": false, + "default_merge_style": "merge", + "default_allow_maintainer_edit": false, + "avatar_url": "", + "internal": false, + "mirror_interval": "", + "object_format_name": "sha256", + "mirror_updated": "0001-01-01T00:00:00Z", + "topics": [], + "licenses": [] + } + }, + "head": { + "label": "PR_openQA#11", + "ref": "PR_openQA#11", + "sha": "71de5ba8c2289e20a07a20d1f836c37ee6437803435425a7cec507004457cc52", + "repo_id": 91295, + "repo": { + "id": 91295, + "owner": { + "id": 181, + "login": "products", + "login_name": "", + "source_id": 0, + "full_name": "", + "email": "", + "avatar_url": "https://src.opensuse.org/avatars/86024cad1e83101d97359d7351051156", + "html_url": "https://src.opensuse.org/products", + "language": "", + "is_admin": false, + "last_login": "0001-01-01T00:00:00Z", + "created": "2023-09-20T11:20:19+02:00", + "restricted": false, + "active": false, + "prohibit_login": false, + "location": "", + "website": "", + "description": "", + "visibility": "public", + "followers_count": 0, + "following_count": 0, + "starred_repos_count": 0, + "username": "products" + }, + "name": "PackageHub", + "full_name": "products/PackageHub", + "description": "", + "empty": false, + "private": false, + "fork": false, + "template": false, + "mirror": false, + "size": 9297, + "language": "", + "languages_url": "https://src.opensuse.org/api/v1/repos/products/PackageHub/languages", + "html_url": "https://src.opensuse.org/products/PackageHub", + "url": "https://src.opensuse.org/api/v1/repos/products/PackageHub", + "link": "", + "ssh_url": "gitea@src.opensuse.org:products/PackageHub.git", + "clone_url": "https://src.opensuse.org/products/PackageHub.git", + "original_url": "", + "website": "", + "stars_count": 1, + "forks_count": 8, + "watchers_count": 14, + "open_issues_count": 0, + "open_pr_counter": 13, + "release_counter": 0, + "default_branch": "leap-16.0", + "archived": false, + "created_at": "2024-09-17T14:31:57+02:00", + "updated_at": "2025-10-06T15:24:40+02:00", + "archived_at": "1970-01-01T01:00:00+01:00", + "permissions": { + "admin": false, + "push": true, + "pull": true + }, + "has_issues": true, + "internal_tracker": { + "enable_time_tracker": false, + "allow_only_contributors_to_track_time": true, + "enable_issue_dependencies": true + }, + "has_wiki": false, + "has_pull_requests": true, + "has_projects": false, + "projects_mode": "all", + "has_releases": false, + "has_packages": false, + "has_actions": true, + "ignore_whitespace_conflicts": false, + "allow_merge_commits": true, + "allow_rebase": true, + "allow_rebase_explicit": true, + "allow_squash_merge": true, + "allow_fast_forward_only_merge": true, + "allow_rebase_update": true, + "allow_manual_merge": true, + "autodetect_manual_merge": true, + "default_delete_branch_after_merge": false, + "default_merge_style": "merge", + "default_allow_maintainer_edit": false, + "avatar_url": "", + "internal": false, + "mirror_interval": "", + "object_format_name": "sha256", + "mirror_updated": "0001-01-01T00:00:00Z", + "topics": [], + "licenses": [] + } + }, + "merge_base": "61505d870aa91436971e71508c07500633ed485dc1d1417ac968a85f1d9511c8", + "due_date": null, + "created_at": "2025-10-06T15:24:38+02:00", + "updated_at": "2025-10-06T15:41:54+02:00", + "closed_at": null, + "pin_order": 0 + }, + "requested_reviewer": { + "id": 1008, + "login": "autogits_obs_staging_bot", + "login_name": "", + "source_id": 0, + "full_name": "", + "email": "autogits_obs_staging_bot@noreply.src.opensuse.org", + "avatar_url": "https://src.opensuse.org/avatars/9aa9b21c0beaf80d4af7a0fca8a326862127f8b5fa68e47d0870800441ced967", + "html_url": "https://src.opensuse.org/autogits_obs_staging_bot", + "language": "", + "is_admin": false, + "last_login": "0001-01-01T00:00:00Z", + "created": "2024-07-06T14:31:34+02:00", + "restricted": false, + "active": false, + "prohibit_login": false, + "location": "", + "website": "", + "description": "I stage proposed changes and see if they build.", + "visibility": "public", + "followers_count": 0, + "following_count": 0, + "starred_repos_count": 0, + "username": "autogits_obs_staging_bot" + }, + "repository": { + "id": 91295, + "owner": { + "id": 181, + "login": "products", + "login_name": "", + "source_id": 0, + "full_name": "", + "email": "", + "avatar_url": "https://src.opensuse.org/avatars/86024cad1e83101d97359d7351051156", + "html_url": "https://src.opensuse.org/products", + "language": "", + "is_admin": false, + "last_login": "0001-01-01T00:00:00Z", + "created": "2023-09-20T11:20:19+02:00", + "restricted": false, + "active": false, + "prohibit_login": false, + "location": "", + "website": "", + "description": "", + "visibility": "public", + "followers_count": 0, + "following_count": 0, + "starred_repos_count": 0, + "username": "products" + }, + "name": "PackageHub", + "full_name": "products/PackageHub", + "description": "", + "empty": false, + "private": false, + "fork": false, + "template": false, + "mirror": false, + "size": 9297, + "language": "", + "languages_url": "https://src.opensuse.org/api/v1/repos/products/PackageHub/languages", + "html_url": "https://src.opensuse.org/products/PackageHub", + "url": "https://src.opensuse.org/api/v1/repos/products/PackageHub", + "link": "", + "ssh_url": "gitea@src.opensuse.org:products/PackageHub.git", + "clone_url": "https://src.opensuse.org/products/PackageHub.git", + "original_url": "", + "website": "", + "stars_count": 1, + "forks_count": 8, + "watchers_count": 14, + "open_issues_count": 0, + "open_pr_counter": 13, + "release_counter": 0, + "default_branch": "leap-16.0", + "archived": false, + "created_at": "2024-09-17T14:31:57+02:00", + "updated_at": "2025-10-06T15:24:40+02:00", + "archived_at": "1970-01-01T01:00:00+01:00", + "permissions": { + "admin": false, + "push": false, + "pull": true + }, + "has_issues": true, + "internal_tracker": { + "enable_time_tracker": false, + "allow_only_contributors_to_track_time": true, + "enable_issue_dependencies": true + }, + "has_wiki": false, + "has_pull_requests": true, + "has_projects": false, + "projects_mode": "all", + "has_releases": false, + "has_packages": false, + "has_actions": true, + "ignore_whitespace_conflicts": false, + "allow_merge_commits": true, + "allow_rebase": true, + "allow_rebase_explicit": true, + "allow_squash_merge": true, + "allow_fast_forward_only_merge": true, + "allow_rebase_update": true, + "allow_manual_merge": true, + "autodetect_manual_merge": true, + "default_delete_branch_after_merge": false, + "default_merge_style": "merge", + "default_allow_maintainer_edit": false, + "avatar_url": "", + "internal": false, + "mirror_interval": "", + "object_format_name": "sha256", + "mirror_updated": "0001-01-01T00:00:00Z", + "topics": [], + "licenses": [] + }, + "sender": { + "id": 1008, + "login": "autogits_obs_staging_bot", + "login_name": "", + "source_id": 0, + "full_name": "", + "email": "autogits_obs_staging_bot@noreply.src.opensuse.org", + "avatar_url": "https://src.opensuse.org/avatars/9aa9b21c0beaf80d4af7a0fca8a326862127f8b5fa68e47d0870800441ced967", + "html_url": "https://src.opensuse.org/autogits_obs_staging_bot", + "language": "", + "is_admin": false, + "last_login": "0001-01-01T00:00:00Z", + "created": "2024-07-06T14:31:34+02:00", + "restricted": false, + "active": false, + "prohibit_login": false, + "location": "", + "website": "", + "description": "I stage proposed changes and see if they build.", + "visibility": "public", + "followers_count": 0, + "following_count": 0, + "starred_repos_count": 0, + "username": "autogits_obs_staging_bot" + }, + "commit_id": "", + "review": { + "type": "pull_request_review_approved", + "content": "Build successful" + } +} \ No newline at end of file From 6962a4a7fba3410dc7a3d496f30d3e4ffc2bf966 Mon Sep 17 00:00:00 2001 From: Santiago Zarate Date: Tue, 7 Oct 2025 10:29:41 +0200 Subject: [PATCH 14/14] Move simulation of build finished to its own function --- amqp-listen-gitea.py | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/amqp-listen-gitea.py b/amqp-listen-gitea.py index 5908e65f..2d82ac22 100644 --- a/amqp-listen-gitea.py +++ b/amqp-listen-gitea.py @@ -88,18 +88,15 @@ def simulate(args): with open(json_file, 'r') as f: content = f.read() data = json.loads(content) - - if args.simulate_build_finished_event and args.build_bot: - print("build_finished_event properly initialized") - - json_file = args.simulate_build_finished_event - with open(json_file, 'r') as f: - content = f.read() - build_data = json.loads(content) - return handle_build_finished(build_data, args) - handle_review_request(data, args) +def simulate_build_finished_event(args): + print('================= simulate_build_finished_event') + json_file = args.simulate_build_finished_event + with open(json_file, 'r') as f: + content = f.read() + build_data = json.loads(content) + return handle_build_finished(build_data, args) def handle_review_request(data, args): print("============== handle_review_request") @@ -299,5 +296,7 @@ def fetch_url(url, request_type="text"): args = parse_args() if args.simulate_review_requested_event: simulate(args) + elif(args.simulate_build_finished_event and args.build_bot): + simulate_build_finished_event(args) else: listen(args)