From: Patrick Donnelly Date: Sat, 11 Jul 2026 19:09:47 +0000 (-0400) Subject: script/ptl-tool: map supported PR labels to Redmine QA tags X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=0bc6dfe560377be3f3f700f0e29cf28657c3d269;p=ceph.git script/ptl-tool: map supported PR labels to Redmine QA tags Introduce a supported whitelist of component tags (e.g., rgw, cephfs, rbd, cephadm) and automatically extract matching labels from the queued GitHub pull requests during integration branch builds. When building or updating a Redmine QA tracking ticket: * Append matching component tags directly to each PR line in the ticket description (e.g., `(tags: rgw, cephfs)`). * Populate the `tag_list` attribute on the Redmine issue to seamlessly integrate with the RedmineUP Tags plugin. * When updating an existing QA ticket, preserve any pre-existing tags already attached to the issue and merge them with the active PR tags. Signed-off-by: Patrick Donnelly --- diff --git a/src/script/ptl-tool.py b/src/script/ptl-tool.py index 0da830d29fa..df7731c70c4 100755 --- a/src/script/ptl-tool.py +++ b/src/script/ptl-tool.py @@ -123,6 +123,18 @@ except FileNotFoundError: pass REDMINE_API_KEY = os.getenv("PTL_TOOL_REDMINE_API_KEY", REDMINE_API_KEY) SPECIAL_BRANCHES = ('main', 'luminous', 'jewel', 'HEAD') +SUPPORTED_QA_TAGS = { + 'cephadm', + 'cephfs', + 'core', + 'dashboard', + 'libcephsqlite', + 'nvme', + 'orch', + 'rbd', + 'rgw', + 'upgrades', +} TEST_BRANCH = os.getenv("PTL_TOOL_TEST_BRANCH", "wip-{user}-testing-%Y%m%d.%H%M%S") USER = os.getenv("PTL_TOOL_USER", getuser()) @@ -379,7 +391,15 @@ def get_pr_info(session, pr): def get_pr_tracker_string(session, pr, response=None): if not response: response = get_pr_info(session, pr) - return f'* "PR #{pr}":{response["html_url"]} -- {response["title"].strip()}' + + pr_tags = [] + for lbl in response.get('labels', []): + lbl_name = lbl.get('name', '') + if lbl_name.lower() in SUPPORTED_QA_TAGS: + pr_tags.append(lbl_name.lower()) + + tag_str = f" (tags: {', '.join(sorted(pr_tags))})" if pr_tags else "" + return f'* "PR #{pr}":{response["html_url"]} -- {response["title"].strip()}{tag_str}' def get(session, url, params=None, paging=True): if params is None: @@ -1696,6 +1716,18 @@ def manage_qa_tracker(args, R, session, branch, prs, tag, qa_tracker_description if args.qa_private: issue_kwargs['is_private'] = True + pr_tags = set() + for pr in prs: + pr_info = get_pr_info(session, pr) + for lbl in pr_info.get('labels', []): + lbl_name = lbl.get('name', '') + if lbl_name.lower() in SUPPORTED_QA_TAGS: + pr_tags.add(lbl_name.lower()) + + if pr_tags: + log.info(f"Adding supported Redmine tags from PR labels: {', '.join(sorted(list(pr_tags)))}") + issue_kwargs['tag_list'] = sorted(list(pr_tags)) + if args.update_qa: issue = R.issue.get(args.update_qa) if issue.project.id != project.id: @@ -1705,6 +1737,20 @@ def manage_qa_tracker(args, R, session, branch, prs, tag, qa_tracker_description log.error(f"issue {issue.url} tracker {issue.tracker} does not match {tracker}") sys.exit(1) + if hasattr(issue, 'tag_list') and issue.tag_list: + if isinstance(issue.tag_list, (list, tuple)): + pr_tags.update(str(t) for t in issue.tag_list) + elif isinstance(issue.tag_list, str): + pr_tags.update(t.strip() for t in issue.tag_list.split(',') if t.strip()) + elif hasattr(issue, 'tags') and issue.tags: + if isinstance(issue.tags, (list, tuple)): + pr_tags.update(str(t) for t in issue.tags) + elif isinstance(issue.tags, str): + pr_tags.update(t.strip() for t in issue.tags.split(',') if t.strip()) + + if pr_tags: + issue_kwargs['tag_list'] = sorted(list(pr_tags)) + old_branch = "unknown" for cf in issue.custom_fields: if cf.id in (REDMINE_CUSTOM_FIELD_ID_SHAMAN_BUILD, REDMINE_CUSTOM_FIELD_ID_QA_RUNS):