]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
script/ptl-tool: map supported PR labels to Redmine QA tags
authorPatrick Donnelly <pdonnell@ibm.com>
Sat, 11 Jul 2026 19:09:47 +0000 (15:09 -0400)
committerPatrick Donnelly <pdonnell@ibm.com>
Mon, 13 Jul 2026 00:49:30 +0000 (20:49 -0400)
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 <pdonnell@ibm.com>
src/script/ptl-tool.py

index 0da830d29faab8b67edc9678b930450013bf9c49..df7731c70c41d298f6002de3f8ebf70274573479 100755 (executable)
@@ -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):