get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

GET /api/1.2/patches/2232789/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 2232789,
    "url": "http://patchwork.ozlabs.org/api/1.2/patches/2232789/?format=api",
    "web_url": "http://patchwork.ozlabs.org/project/gcc/patch/bmm.hi8lco6rjs.gcc.gcc-TEST.rearnsha.149.1.1@forge-stage.sourceware.org/",
    "project": {
        "id": 17,
        "url": "http://patchwork.ozlabs.org/api/1.2/projects/17/?format=api",
        "name": "GNU Compiler Collection",
        "link_name": "gcc",
        "list_id": "gcc-patches.gcc.gnu.org",
        "list_email": "gcc-patches@gcc.gnu.org",
        "web_url": null,
        "scm_url": null,
        "webscm_url": null,
        "list_archive_url": "",
        "list_archive_url_format": "",
        "commit_url_format": ""
    },
    "msgid": "<bmm.hi8lco6rjs.gcc.gcc-TEST.rearnsha.149.1.1@forge-stage.sourceware.org>",
    "list_archive_url": null,
    "date": "2026-05-05T09:17:12",
    "name": "[v1,1/1] Forge: Add scaffolding for managing forge labels",
    "commit_ref": null,
    "pull_url": null,
    "state": "new",
    "archived": false,
    "hash": "9324c6b522ac483ee1c129028a28039a7c4ac3dc",
    "submitter": {
        "id": 92169,
        "url": "http://patchwork.ozlabs.org/api/1.2/people/92169/?format=api",
        "name": "Richard Earnshaw via Sourceware Forge",
        "email": "forge-bot+rearnsha@forge-stage.sourceware.org"
    },
    "delegate": null,
    "mbox": "http://patchwork.ozlabs.org/project/gcc/patch/bmm.hi8lco6rjs.gcc.gcc-TEST.rearnsha.149.1.1@forge-stage.sourceware.org/mbox/",
    "series": [
        {
            "id": 502793,
            "url": "http://patchwork.ozlabs.org/api/1.2/series/502793/?format=api",
            "web_url": "http://patchwork.ozlabs.org/project/gcc/list/?series=502793",
            "date": "2026-05-05T09:17:11",
            "name": "WIP: Forge: Add scaffolding for managing forge labels",
            "version": 1,
            "mbox": "http://patchwork.ozlabs.org/series/502793/mbox/"
        }
    ],
    "comments": "http://patchwork.ozlabs.org/api/patches/2232789/comments/",
    "check": "pending",
    "checks": "http://patchwork.ozlabs.org/api/patches/2232789/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org>",
        "X-Original-To": [
            "incoming@patchwork.ozlabs.org",
            "gcc-patches@gcc.gnu.org"
        ],
        "Delivered-To": [
            "patchwork-incoming@legolas.ozlabs.org",
            "gcc-patches@gcc.gnu.org"
        ],
        "Authentication-Results": [
            "legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org\n (client-ip=2620:52:6:3111::32; helo=vm01.sourceware.org;\n envelope-from=gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org;\n receiver=patchwork.ozlabs.org)",
            "sourceware.org; dmarc=none (p=none dis=none)\n header.from=forge-stage.sourceware.org",
            "sourceware.org;\n spf=pass smtp.mailfrom=forge-stage.sourceware.org",
            "server2.sourceware.org;\n arc=none smtp.remote-ip=38.145.34.39"
        ],
        "Received": [
            "from vm01.sourceware.org (vm01.sourceware.org\n [IPv6:2620:52:6:3111::32])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange x25519 server-signature ECDSA (secp384r1) server-digest SHA384)\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4g8tLL3v6Gz1y04\n\tfor <incoming@patchwork.ozlabs.org>; Tue, 05 May 2026 19:21:30 +1000 (AEST)",
            "from vm01.sourceware.org (localhost [127.0.0.1])\n\tby sourceware.org (Postfix) with ESMTP id 8414A4BA79BB\n\tfor <incoming@patchwork.ozlabs.org>; Tue,  5 May 2026 09:21:28 +0000 (GMT)",
            "from forge-stage.sourceware.org (vm08.sourceware.org [38.145.34.39])\n by sourceware.org (Postfix) with ESMTPS id 267634BA7994\n for <gcc-patches@gcc.gnu.org>; Tue,  5 May 2026 09:18:11 +0000 (GMT)",
            "from forge-stage.sourceware.org (localhost [IPv6:::1])\n (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n key-exchange x25519 server-signature ECDSA (prime256v1) server-digest SHA256)\n (No client certificate requested)\n by forge-stage.sourceware.org (Postfix) with ESMTPS id AB12742C44;\n Tue, 05 May 2026 09:18:10 +0000 (UTC)"
        ],
        "DKIM-Filter": [
            "OpenDKIM Filter v2.11.0 sourceware.org 8414A4BA79BB",
            "OpenDKIM Filter v2.11.0 sourceware.org 267634BA7994"
        ],
        "DMARC-Filter": "OpenDMARC Filter v1.4.2 sourceware.org 267634BA7994",
        "ARC-Filter": "OpenARC Filter v1.0.0 sourceware.org 267634BA7994",
        "ARC-Seal": "i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1777972691; cv=none;\n b=mTWWPlzN4vPX64V9hw5OIWuUeUal9GoSAKZxGJMnfoK3IRYa4KC2iMxsQPi6dFELyxP2Nnnx9zJLL+P+b3jZkbYghX4+lsDcfK5YiEzraSTRaathh+d+SlTdqfU9yR8MfOE7WzKKnfOD2sih3hTMJruz849Pi0+9Nl64o60QQI8=",
        "ARC-Message-Signature": "i=1; a=rsa-sha256; d=sourceware.org; s=key;\n t=1777972691; c=relaxed/simple;\n bh=n0YCe44XbHo9wSmb5+McHQBWl99vBAss85ogw8dY4jM=;\n h=From:Date:Subject:To:Message-ID;\n b=IszdjE16T5HtQeyCZ6uHZwV+vkGRI11I4qazAAyWCgXmg4/dooiDLPYKZl2Mnoy893snRYk0BM8stjAF723c0Sb4AxNskdFLHfeMGpzJozKh5E/PDR56wx52Bcsu73bRyQoVE0Q1P69II94bjE7bdhux2Wv/zFlFurq5i1m5rnA=",
        "ARC-Authentication-Results": "i=1; server2.sourceware.org",
        "From": "Richard Earnshaw via Sourceware Forge\n <forge-bot+rearnsha@forge-stage.sourceware.org>",
        "Date": "Tue, 05 May 2026 09:17:12 +0000",
        "Subject": "[PATCH v1 1/1] Forge: Add scaffolding for managing forge labels",
        "To": "gcc-patches mailing list <gcc-patches@gcc.gnu.org>",
        "Cc": "claudio.bantaloukas@arm.com",
        "Message-ID": "\n <bmm.hi8lco6rjs.gcc.gcc-TEST.rearnsha.149.1.1@forge-stage.sourceware.org>",
        "X-Mailer": "batrachomyomachia",
        "X-Requested-Reviewer": "rdfm",
        "X-Pull-Request-Organization": "gcc",
        "X-Pull-Request-Repository": "gcc-TEST",
        "X-Pull-Request": "https://forge.sourceware.org/gcc/gcc-TEST/pulls/149",
        "References": "\n <bmm.hi8lco6rjs.gcc.gcc-TEST.rearnsha.149.1.0@forge-stage.sourceware.org>",
        "In-Reply-To": "\n <bmm.hi8lco6rjs.gcc.gcc-TEST.rearnsha.149.1.0@forge-stage.sourceware.org>",
        "X-Patch-URL": "\n https://forge.sourceware.org/rearnsha/gcc-TEST/commit/59109ed260b8a6064ba8c5a41335d3caf6ee82b6",
        "X-BeenThere": "gcc-patches@gcc.gnu.org",
        "X-Mailman-Version": "2.1.30",
        "Precedence": "list",
        "List-Id": "Gcc-patches mailing list <gcc-patches.gcc.gnu.org>",
        "List-Unsubscribe": "<https://gcc.gnu.org/mailman/options/gcc-patches>,\n <mailto:gcc-patches-request@gcc.gnu.org?subject=unsubscribe>",
        "List-Archive": "<https://gcc.gnu.org/pipermail/gcc-patches/>",
        "List-Post": "<mailto:gcc-patches@gcc.gnu.org>",
        "List-Help": "<mailto:gcc-patches-request@gcc.gnu.org?subject=help>",
        "List-Subscribe": "<https://gcc.gnu.org/mailman/listinfo/gcc-patches>,\n <mailto:gcc-patches-request@gcc.gnu.org?subject=subscribe>",
        "Reply-To": "gcc-patches mailing list <gcc-patches@gcc.gnu.org>,\n claudio.bantaloukas@arm.com, rearnsha@arm.com",
        "Errors-To": "gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org"
    },
    "content": "From: Richard Earnshaw <rearnsha@arm.com>\n\nAdd some scaffolding for managing labels used by the forge.  This\npatch handles some general infrastructure to read a 'database' of\nlabels, an initial set of lables and a script to manage the list of\nlabels on the forge instance.  It makes use of the forge's REST API to\nautomate the process, thus making it simple for a user with\nappropriate privilages to update the list with minimal effort.\n\nThe classify.py script takes a list of file paths and applies the\nmatch rules, printing out the labels that would apply to each filename.\nYou can see the effects by running\n  (cd $GCC_SRC_BASE; find . -type f -print) | ./classify.py\n\nI expect a future patch to use the matching data to automatically\nlabel merge requests with the relevant labels as part of the initial\ntriaging process.\n\ncontrib/ChangeLog:\n\n\t* forge/forgelabels.py: New file.\n\t* forge/labels.yaml: New file.\n\t* forge/update-labels.py: New file.\n\t* forge/classify.py: New file.\n---\n contrib/forge/classify.py      |  88 ++++\n contrib/forge/forgelabels.py   | 201 +++++++\n contrib/forge/labels.yaml      | 926 +++++++++++++++++++++++++++++++++\n contrib/forge/update-labels.py | 151 ++++++\n 4 files changed, 1366 insertions(+)\n create mode 100755 contrib/forge/classify.py\n create mode 100755 contrib/forge/forgelabels.py\n create mode 100644 contrib/forge/labels.yaml\n create mode 100755 contrib/forge/update-labels.py",
    "diff": "diff --git a/contrib/forge/classify.py b/contrib/forge/classify.py\nnew file mode 100755\nindex 000000000000..da77c9c72390\n--- /dev/null\n+++ b/contrib/forge/classify.py\n@@ -0,0 +1,88 @@\n+#!/usr/bin/env python3\n+\n+# Map files in the GCC source tree to forge labels.\n+\n+# Copyright (C) 2026 Free Software Foundation, Inc.\n+#\n+# This file is part of GCC.\n+#\n+# GCC is free software; you can redistribute it and/or modify it under\n+# the terms of the GNU General Public License as published by the Free\n+# Software Foundation; either version 3, or (at your option) any later\n+# version.\n+#\n+# GCC is distributed in the hope that it will be useful, but WITHOUT ANY\n+# WARRANTY; without even the implied warranty of MERCHANTABILITY or\n+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n+# for more details.\n+#\n+# You should have received a copy of the GNU General Public License\n+# along with GCC; see the file COPYING3.  If not see\n+# <http://www.gnu.org/licenses/>.\n+\n+# Note, this file requires python 3.10 or later.\n+\n+import re\n+import sys\n+import forgelabels\n+\n+labels_file = 'labels'\n+\n+class classifier:\n+    def __init__ (self, groups):\n+        self.file_class = []\n+        self.bz_class = []\n+        for g in groups:\n+            if not g.match_defaults or g.match_defaults.mclass != \"file\":\n+                continue\n+            for l in g.labels:\n+                if l.match:\n+                    self.file_class.append (self._file_entry (l.match,\n+                                                              l.full_name))\n+\n+    def map_to_labels (self, name):\n+        labels = []\n+        priority = 100\n+        for fc in self.file_class:\n+            if fc['pattern'].match (name):\n+                if fc['priority'] < priority:\n+                    priority = fc['priority']\n+                    labels = [fc['label']]\n+                elif fc['priority'] == priority:\n+                    labels.append (fc['label'])\n+\n+        return labels\n+\n+    def _file_entry (self, match, label):\n+        priority = match.priority\n+\n+        d = dict()\n+        try:\n+            d['pattern'] = re.compile (match.file2re ())\n+        except Exception as e:\n+            # Re-raise the exception with some additional context\n+            raise Exception (f\"{label}: {str (e)}\")\n+\n+        d['priority'] = priority\n+        d['label'] = label\n+        return d\n+\n+def load ():\n+    \"\"\"\n+    Main entry point to initialize the classifier\n+    \"\"\"\n+    return classifier (forgelabels.load ())\n+\n+def main ():\n+    \"\"\"\n+    Entry point for testing the classifier.\n+    Use it with something like:\n+       (cd srcroot; find . -type f -print) | ./classify.py\n+    \"\"\"\n+    my_classifier = load ()\n+    for f in sys.stdin.readlines ():\n+        labels = my_classifier.map_to_labels (f[1:].strip ('\\n'))\n+        print (f\"{f.strip ('\\n')}: {labels}\")\n+\n+if __name__ == \"__main__\":\n+    main ()\ndiff --git a/contrib/forge/forgelabels.py b/contrib/forge/forgelabels.py\nnew file mode 100755\nindex 000000000000..b4b42ba0feb4\n--- /dev/null\n+++ b/contrib/forge/forgelabels.py\n@@ -0,0 +1,201 @@\n+#! /usr/bin/env python3\n+\n+# Read the list of label data for a forgejo instance of GCC\n+\n+# Copyright (C) 2026 Free Software Foundation, Inc.\n+#\n+# This file is part of GCC.\n+#\n+# GCC is free software; you can redistribute it and/or modify it under\n+# the terms of the GNU General Public License as published by the Free\n+# Software Foundation; either version 3, or (at your option) any later\n+# version.\n+#\n+# GCC is distributed in the hope that it will be useful, but WITHOUT ANY\n+# WARRANTY; without even the implied warranty of MERCHANTABILITY or\n+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n+# for more details.\n+#\n+# You should have received a copy of the GNU General Public License\n+# along with GCC; see the file COPYING3.  If not see\n+# <http://www.gnu.org/licenses/>.\n+\n+# Variables needed by the script.  Can be overridden by setting the\n+# same name in the environment\n+\n+import yaml\n+\n+# Prefer the libYAML implementations if available.  Fall back to the\n+# pure python versions as a backup.\n+try:\n+    from yaml import CLoader as Loader, CDumper as Dumper\n+except:\n+    from yaml import Loader, Dumper\n+\n+labels_file = \"labels.yaml\"\n+\n+class match_defaults:\n+    def __init__(self, md_data):\n+        self.mclass = 'file'\n+        if 'class' in md_data:\n+            if (md_data['class'] == \"file\"\n+                or md_data['class'] == \"BZ\"):\n+                self.mclass = md_data['class']\n+            else:\n+                raise Exception (\"Unsupported match class: {md_data['class']}\")\n+\n+        # todo: Add BZ class support\n+\n+class label_match:\n+    def __init__(self, lm_data):\n+        self.file = None\n+        self.priority = 1\n+        if 'file' in lm_data:\n+            self.file = lm_data['file']\n+        if 'priority' in lm_data:\n+            self.priority = lm_data['priority']\n+        # todo: Add BZ match support\n+\n+    def file2re(self):\n+        \"\"\"\n+        Convert the extended glob file entry to a standard regular expression.\n+\n+        Supported features:\n+        ^/ at the start of an entry anchors to the root of the file tree.\n+        \\<char> passes <char> through to the RE compiler, without any of\n+           the interpretations below.\n+        /**/ matches an arbitrary depth of directories.\n+        * matches any character except '/'.\n+        + matches the literal '+'.\n+        . matches the literal '.'.\n+        (...|...[|...]+) match any of the alternatives.\n+        \"\"\"\n+        if not self.file:\n+            raise Exception (\"Match rule lacks a 'file' entry\")\n+        template = self.file\n+        pos = 0\n+        depth = 0\n+        last_char = None\n+        pattern = r''\n+        length = len (template)\n+        if template[pos] == '^':\n+            pattern += r'^'\n+            pos += 1\n+            # Don't update last char\n+        else:\n+            pattern += r'.*/'\n+\n+        while pos < length:\n+            if template[pos] == '\\\\' and pos + 1 < length:\n+                pos += 1\n+                pattern += template[pos]\n+            # '*' is mapped to '[^/]*' unless the following characters are\n+            # also '*/', in which case we match '(.*/)*'\n+            elif template[pos] == '*':\n+                if pos + 2 < length and template[:3] == '**/':\n+                    pattern += r'(:?.*/)*'\n+                    pos += 1\n+                else:\n+                    pattern += r'[^/]*'\n+            elif template[pos] == '+':\n+                pattern += r'\\+'\n+            elif template[pos] == '(':\n+                # We don't need any groups from the regex.\n+                pattern += r'(?:'\n+                depth += 1\n+            elif template[pos] == ')':\n+                pattern += r')'\n+                depth -= 1\n+                if depth < 0:\n+                    raise Exception ('Invalid template: ' + template)\n+            elif template[pos] == '.':\n+                pattern += r'\\.'\n+            elif template[pos] == '/':\n+                pattern += r'/'\n+                if (depth > 0\n+                    and pos + 1 < length \n+                    and (template[pos + 1] == '|'\n+                         or template[pos + 1] == ')')):\n+                    # We expect '/|' (or '/)' to appear at the end of\n+                    # an alternative and to mean anything in any\n+                    # subdirectory matched.  But we may need to match\n+                    # files in the alternative, so add an explicit\n+                    # '.*'.\n+                    pattern += r'.*'\n+            else:\n+                pattern += template[pos]\n+            last_char = template[pos]\n+            pos += 1\n+\n+        if depth != 0:\n+            raise Exception ('Invalid template: ' + template)\n+        if last_char != '/':\n+            pattern += '$'\n+\n+        return pattern\n+\n+class label:\n+    def __init__(self, l_data, group):\n+        self.name = None\n+        self.full_name = None\n+        self.desc = None\n+        self.match = None\n+        self.color_val = None\n+        self.group = group\n+        if 'name' in l_data:\n+            self.name = l_data['name']\n+            self.full_name = group.group + '/' + self.name\n+        else:\n+            raise Exception (f\"Missing label name (in group '{group.group}').\")\n+        if 'description' in l_data:\n+            self.desc = l_data['description']\n+        if 'match' in l_data:\n+            self.match = label_match(l_data['match'])\n+    def color(self):\n+        if self.color_val:\n+            return self.color_val\n+        return self.group.color\n+\n+class group:\n+    def __init__(self, gr_data):\n+        # defaults\n+        self.exclusive = False\n+        self.color = \"#ff0000\"  # Red\n+        self.match_defaults = None\n+        self.labels = []\n+\n+        if 'group' in gr_data:\n+            self.group = gr_data['group']\n+        else:\n+            raise Exception ('All groups must specify their name')\n+        if 'color' in gr_data:\n+            self.color = gr_data['color']\n+        if 'exclusive' in gr_data:\n+            self.exclusive = gr_data['exclusive']\n+        if 'match_defaults' in gr_data:\n+            self.match_defaults = match_defaults(gr_data['match_defaults'])\n+        if 'labels' in gr_data:\n+            for l in gr_data['labels']:\n+                self.labels.append(label(l, self))\n+        else:\n+            raise Exception (f\"Group {self.group} must contain at least one label\")\n+\n+def load():\n+    with open(labels_file) as f:\n+        groups = []\n+        data = yaml.load (f, Loader=Loader)\n+\n+        try:\n+            for g in data['label_data']:\n+                groups.append(group(g))\n+\n+        except Exception as e:\n+            raise e\n+            return\n+    return groups\n+\n+def main():\n+    print (load())\n+\n+if __name__ == \"__main__\":\n+    main()\ndiff --git a/contrib/forge/labels.yaml b/contrib/forge/labels.yaml\nnew file mode 100644\nindex 000000000000..4abe4779b975\n--- /dev/null\n+++ b/contrib/forge/labels.yaml\n@@ -0,0 +1,926 @@\n+# Provisional list of labels for the gcc forge:\n+#\n+# Copyright (C) 2026 Free Software Foundation, Inc.\n+#\n+# This file is part of GCC.\n+#\n+# GCC is free software; you can redistribute it and/or modify it under\n+# the terms of the GNU General Public License as published by the Free\n+# Software Foundation; either version 3, or (at your option) any later\n+# version.\n+#\n+# GCC is distributed in the hope that it will be useful, but WITHOUT ANY\n+# WARRANTY; without even the implied warranty of MERCHANTABILITY or\n+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n+# for more details.\n+#\n+# You should have received a copy of the GNU General Public License\n+# along with GCC; see the file COPYING3.  If not see\n+# <http://www.gnu.org/licenses/>.\n+\n+# Tags are not exclusive unless otherwise stated.\n+\n+# Note, *** indicates that this matches a strict category, but perhaps\n+# we shouldn't permit these in labels.\n+\n+# Format of this file:\n+#\n+#   We currently recognize three classes matching rule for auto-applying\n+#   labels: BZ, file and none.\n+#   The matching rules are inherrited up the data scopes with the inner\n+#   most rule taking precedence.  If no rule can be found, then the\n+#   default rule of 'none' is applied.\n+#   - BZ\n+#     If the patch cover letter references a Bugzilla ticket, the ticket\n+#     number will be looked up in the Bugzilla database and the\n+#     appropriate data used to apply the relevant label.\n+#   - file\n+#     The extended glob patterns are matched against the files modified\n+#     and the label is attached if the pattern matches and no higher\n+#     priority matches exist.  The default priority for a match is 1\n+#   - none\n+#     Can be used to disable a label from being selected by matching\n+#     when a default class would otherwise be inherrited.\n+\n+\n+label_data: \n+  # Bug reports\n+  # All of these labels are expected to be automatically scraped from\n+  # the primary (first-referenced) bugzilla entry that is identified\n+  # from the cover text of a patch.  Note that they will not be\n+  # automatically updated if the bugzilla entry is changed after the\n+  # pull request has been created.\n+  - group: Bug\n+    # Labels relating to bugs with a 'regression' marker in the\n+    # bug summary.\n+    exclusive: false\n+    color: \"bd0000\"\n+    labels:\n+      - name: Regression\n+        description: \"The referenced Bugzilla ticket is a regression\"\n+        match:\n+          class: BZ\n+          field: summary\n+          value: \"imatch(\\\\[[^\\\\]]*regression\\\\])\"\n+  - group: Bug/Importance\n+    exclusive: true\n+    color: \"f06d00\"\n+    match_defaults:\n+      class: BZ\n+      field: importance\n+    labels:\n+      - name: \"P1\"\n+        description: \"The Bugzilla ticket has priority P1\"\n+        match:\n+          value: \"== 'P1'\"\n+      - name: \"P2\"\n+        description: \"The Bugzilla ticket has priority P2\"\n+        match:\n+          value: \"== 'P2'\"\n+      - name: \"P3\"\n+        description: \"The Bugzilla ticket has priority P3\"\n+        match:\n+          value: \"== 'P3'\"\n+      - name: \"P4\"\n+        description: \"The Bugzilla ticket has priority P4\"\n+        match:\n+          value: \"== 'P4'\"\n+      - name: \"P5\"\n+        description: \"The Bugzilla ticket has priority P5\"\n+        match:\n+          value: \"== 'P5'\"\n+  # Labels relating to bugs with a specific component.  The final\n+  # part of the label should be a string match for the component\n+  # field of the BZ entry.\n+  - group: \"Bug/Component\"\n+    exclusive: true\n+    color: \"fbca04\"\n+    match_defaults:\n+      class: BZ\n+      field: component\n+      label_name: true\n+    labels:\n+      - name: \"ada\"\n+        description: \"The Bugzilla component is 'ada'\"\n+      - name: \"algol68\"\n+        description: \"The Bugzilla component is 'algol68'\"\n+      - name: \"analyzer\"\n+        description: \"The Bugzilla component is 'analyzer'\"\n+      - name: \"boehm-gc\"\n+        description: \"The Bugzilla component is 'boehm-gc'\"\n+      - name: \"bootstrap\"\n+        description: \"The Bugzilla component is 'bootstrap'\"\n+      - name: \"c\"\n+        description: \"The Bugzilla component is 'c'\"\n+      - name: \"c++\"\n+        description: \"The Bugzilla component is 'c++'\"\n+      - name: \"cobol\"\n+        description: \"The Bugzilla component is 'cobol'\"\n+      - name: \"d\"\n+        description: \"The Bugzilla component is 'd'\"\n+      - name: \"debug\"\n+        description: \"The Bugzilla component is 'debug'\"\n+      - name: \"demangler\"\n+        description: \"The Bugzilla component is 'demangler'\"\n+      - name: \"diagnostics\"\n+        description: \"The Bugzilla component is 'diagnostics'\"\n+      - name: \"driver\"\n+        description: \"The Bugzilla component is 'driver'\"\n+      - name: \"fortran\"\n+        description: \"The Bugzilla component is 'fortran'\"\n+      - name: \"gcov-profile\"\n+        description: \"The Bugzilla component is 'gcov-profile'\"\n+      - name: \"go\"\n+        description: \"The Bugzilla component is 'go'\"\n+      - name: \"ipa\"\n+        description: \"The Bugzilla component is 'ipa'\"\n+      - name: \"jit\"\n+        description: \"The Bugzilla component is 'jit'\"\n+      - name: \"libbacktrace\"\n+        description: \"The Bugzilla component is 'libbacktrace'\"\n+      - name: \"libcc1\"\n+        description: \"The Bugzilla component is 'libcc1'\"\n+      - name: \"libffi\"\n+        description: \"The Bugzilla component is 'libffi'\"\n+      - name: \"libfortran\"\n+        description: \"The Bugzilla component is 'libfortran'\"\n+      - name: \"libgcc\"\n+        description: \"The Bugzilla component is 'libgcc'\"\n+      - name: \"libgdiagnostics\"\n+        description: \"The Bugzilla component is 'libdiagnostics'\"\n+      - name: \"libgomp\"\n+        description: \"The Bugzilla component is 'libgomp'\"\n+      - name: \"libitm\"\n+        description: \"The Bugzilla component is 'libitm'\"\n+      - name: \"libobjc\"\n+        description: \"The Bugzilla component is 'libobjc'\"\n+      - name: \"libquadmath\"\n+        description: \"The Bugzilla component is 'libquadmath'\"\n+      - name: \"libstdc++\"\n+        description: \"The Bugzilla component is 'libstdc++'\"\n+      - name: \"lto\"\n+        description: \"The Bugzilla component is 'lto'\"\n+      - name: \"middle-end\"\n+        description: \"The Bugzilla component is 'middle-end'\"\n+      - name: \"modula2\"\n+        description: \"The Bugzilla component is 'modula2'\"\n+      - name: \"objc\"\n+        description: \"The Bugzilla component is 'objc'\"\n+      - name: \"other\"\n+        description: \"The Bugzilla component is 'other'\"\n+      - name: \"pch\"\n+        description: \"The Bugzilla component is 'pch'\"\n+      - name: \"pending\"\n+        description: \"The Bugzilla component is 'pending'\"\n+      - name: \"plugins\"\n+        description: \"The Bugzilla component is 'plugins'\"\n+      - name: \"preprocessor\"\n+        description: \"The Bugzilla component is 'preprocessor'\"\n+      - name: \"regression\"\n+        description: \"The Bugzilla component is 'regression'\"\n+      - name: \"rtl-optimization\"\n+        description: \"The Bugzilla component is 'rtl-optimization'\"\n+      - name: \"rust\"\n+        description: \"The Bugzilla component is 'rust'\"\n+      - name: \"sanitizer\"\n+        description: \"The Bugzilla component is 'sanitizer'\"\n+      - name: \"sarif-replay\"\n+        description: \"The Bugzilla component is 'sarif-replay'\"\n+      - name: \"target\"\n+        description: \"The Bugzilla component is 'target'\"\n+      - name: \"testsuite\"\n+        description: \"The Bugzilla component is 'testsuite'\"\n+      - name: \"translation\"\n+        description: \"The Bugzilla component is 'translation'\"\n+      - name: \"tree-optimization\"\n+        description: \"The Bugzilla component is 'tree-optimization'\"\n+      - name: \"web\"\n+        description: \"The Bugzilla component is 'web'\"\n+  # Labels relating to releases (for backporting)\n+  - group: \"Release\"\n+    exclusive: false\n+    color: \"5319e7\"\n+    labels:\n+      - name: \"GCC-13\"\n+        description: \"Consider backporting to GCC-13\"\n+      - name: \"GCC-14\"\n+        description: \"Consider backporting to GCC-14\"\n+      - name: \"GCC-15\"\n+        description: \"Consider backporting to GCC-15\"\n+      - name: \"GCC-16\"\n+        description: \"Consider backporting to GCC-16\"\n+  # Labels related to components\n+  # Note that multiple labels in this section can be applied, based on\n+  # the files modified.\n+  - group: \"General\"\n+    exclusive: false\n+    color: \"006b75\"\n+    match_defaults:\n+      class: \"file\"\n+    labels:\n+      - name: \"config\"\n+        description: \"Affects configure or autoconf scripts\"\n+        match:\n+          file: \"^/(config/|**/*.(in|ac|m4)|**/configure*)\"\n+          priority: 2\n+      - name: \"contrib\"\n+        description: \"Miscellaneous support scripts\"\n+        match:\n+          file: \"^/contrib/\"\n+      - name: \"make\"\n+        description: \"Affects Makefiles or automake\"\n+        match:\n+          file: \"(Makefile(.*)?|*.am)\"\n+          priority: 2\n+      - name: \"driver\"\n+        description: \"GCC main driver program\"\n+        match:\n+          file: \"^/gcc/gcc(-main|-ar)?.(cc|h)\"\n+      - name: \"forge\"\n+        description: \"Forge and CI infrastructure\"\n+        match:\n+          file: \"^/.(forgejo|github)/\"\n+      - name: \"unknown\"\n+        description: \"Catch-all, does not match any other category\"\n+        match:\n+          file: \"*\"\n+          priority: 10\n+      - name: \"gdbhooks\"\n+        description: \"Support for debugging GCC with GDB (gdbhooks.py)\"\n+        match:\n+          file: \"^/gcc/gdb(hooks.py|init.in)\"\n+      - name: \"docs\"\n+        description: \"Changes to the documentation\"\n+        match:\n+          file: \"(docs?/|*.texi)\"\n+      - name: \"web\"\n+        description: \"Changes to the web pages\"\n+        # No match entry!\n+\n+  # Library components\n+  - group: \"Library\"\n+    exclusive: false\n+    color: \"009800\"\n+    match_defaults:\n+      class: \"file\"\n+    labels:\n+      - name: \"libada\"\n+        description: \"Affects libada\"\n+        match:\n+          file: \"^/libada/\"\n+      - name: \"libatomic\"\n+        description: \"Affects libatomic\"\n+        match:\n+          file: \"^/libatomic/\"\n+      - name: \"libbacktrace\"\n+        description: \"Affects libbacktrace\"\n+        match:\n+          file: \"^/libbacktrace/\"\n+      - name: \"libcc1\"\n+        description: \"Affects libcc1\"\n+        match:\n+          file: \"^/libcc1/\"\n+      - name: \"libcody\"\n+        description: \"Affects libcody\"\n+        match:\n+          file: \"^/libcody/\"\n+      - name: \"libcpp\"\n+        description: \"Affects libcpp\"\n+        match:\n+          file: \"^/libcpp/\"\n+      - name: \"libdecnumber\"\n+        description: \"Affects libdecnumber\"\n+        match:\n+          file: \"^/libdecnumber/\"\n+      - name: \"libffi\"\n+        description: \"Affects libffi\"\n+        match:\n+          file: \"^/libffi/\"\n+      - name: \"libgcc\"\n+        description: \"Affects libgcc\"\n+        match:\n+          file: \"^/libgcc/\"\n+      - name: \"libgcobol\"\n+        description: \"Affects libgcobol\"\n+        match:\n+          file: \"^/libgcobol/\"\n+      - name: \"libgfortran\"\n+        description: \"Affects libgfortran\"\n+        match:\n+          file: \"^/libgfortran/\"\n+      - name: \"libgm2\"\n+        description: \"Affects libgm2\"\n+        match:\n+          file: \"^/libgm2/\"\n+      - name: \"libgo\"\n+        description: \"Affects libgo\"\n+        match:\n+          file: \"^/libgo/\"\n+      - name: \"libgomp\"\n+        description: \"Affects libgomp\"\n+        match:\n+          file: \"^/libgomp/\"\n+      - name: \"libgrust\"\n+        description: \"Affects libgrust\"\n+        match:\n+          file: \"^/libgrust/\"\n+      - name: \"libiberty\"\n+        description: \"Affects libiberty\"\n+        match:\n+          file: \"^/(include|libiberty)/\"\n+      - name: \"libitm\"\n+        description: \"Affects libitm\"\n+        match:\n+          file: \"^/libitm/\"\n+      - name: \"libobjc\"\n+        description: \"Affects libobjc\"\n+        match:\n+          file: \"^/libobjc/\"\n+      - name: \"libphobos\"\n+        description: \"Affects libphobos\"\n+        match:\n+          file: \"^/libphobos/\"\n+      - name: \"libquadmath\"\n+        description: \"Affects libquadmath\"\n+        match:\n+          file: \"^/libquadmath/\"\n+      - name: \"libsanitizer\"\n+        description: \"Affects libsanitizer\"\n+        match:\n+          file: \"^/libsanitizer/\"\n+      - name: \"libssp\"\n+        description: \"Affects libssp\"\n+        match:\n+          file: \"^/libssp/\"\n+      - name: \"libstdc++\"\n+        description: \"Affects libstdc++\"\n+        match:\n+          file: \"^/libstdc++-v3/\"\n+      - name: \"libvtv\"\n+        description: \"Affects libvtv\"\n+        match:\n+          file: \"^/libvtv/\"\n+      - name: \"zlib\"\n+        description: \"Affects zlib\"\n+        match:\n+          file: \"^/zlib/\"\n+  # CPU targets (in compiler or in libraries)\n+  - group: \"Target\"\n+    exclusive: false\n+    color: \"70c24a\"\n+    match_defaults:\n+      class: \"file\"\n+    labels:\n+      - name: \"aarch64\"\n+        description: \"Affects the aarch64 target\"\n+        match:\n+          file: \"config/aarch64/\"\n+      - name: \"alpha\"\n+        description: \"Affects the alpha target\"\n+        match:\n+          file: \"config/alpha/\"\n+      - name: \"arc\"\n+        description: \"Affects the arc target\"\n+        match:\n+          file: \"config/arc/\"\n+      - name: \"arm\"\n+        description: \"Affects the arm target\"\n+        match:\n+          file: \"config/arm/\"\n+      - name: \"avr\"\n+        description: \"Affects the avr target\"\n+        match:\n+          file: \"config/avr/\"\n+      - name: \"bfin\"\n+        description: \"Affects the bfin target\"\n+        match:\n+          file: \"config/bfin/\"\n+      - name: \"bpf\"\n+        description: \"Affects the bpf target\"\n+        match:\n+          file: \"config/bpf/\"\n+      - name: \"c6x\"\n+        description: \"Affects the c6x target\"\n+        match:\n+          file: \"config/c6x/\"\n+      - name: \"cris\"\n+        description: \"Affects the cris target\"\n+        match:\n+          file: \"config/cris/\"\n+      - name: \"csky\"\n+        description: \"Affects the csky target\"\n+        match:\n+          file: \"config/csky/\"\n+      - name: \"epiphany\"\n+        description: \"Affects the epiphany target\"\n+        match:\n+          file: \"config/epiphany/\"\n+      - name: \"fr30\"\n+        description: \"Affects the fr30 target\"\n+        match:\n+          file: \"config/fr30/\"\n+      - name: \"frv\"\n+        description: \"Affects the frv target\"\n+        match:\n+          file: \"config/frv/\"\n+      - name: \"ft32\"\n+        description: \"Affects the ft32 target\"\n+        match:\n+          file: \"config/ft32/\"\n+      - name: \"gcn\"\n+        description: \"Affects the gcn target\"\n+        match:\n+          file: \"config/gcn/\"\n+      - name: \"h8300\"\n+        description: \"Affects the h8300 target\"\n+        match:\n+          file: \"config/h8300/\"\n+      - name: \"i386\"\n+        description: \"Affects the i386 target\"\n+        match:\n+          file: \"config/i386/\"\n+      - name: \"ia64\"\n+        description: \"Affects the ia64 target\"\n+        match:\n+          file: \"config/ia64/\"\n+      - name: \"iq2000\"\n+        description: \"Affects the iq2000 target\"\n+        match:\n+          file: \"config/iq2000/\"\n+      - name: \"lm32\"\n+        description: \"Affects the lm32 target\"\n+        match:\n+          file: \"config/lm32/\"\n+      - name: \"loongarch\"\n+        description: \"Affects the loongarch target\"\n+        match:\n+          file: \"config/loongarch/\"\n+      - name: \"m32c\"\n+        description: \"Affects the m32c target\"\n+        match:\n+          file: \"config/m32c/\"\n+      - name: \"m32r\"\n+        description: \"Affects the m32r target\"\n+        match:\n+          file: \"config/m32r/\"\n+      - name: \"m68k\"\n+        description: \"Affects the m68k target\"\n+        match:\n+          file: \"config/m68k/\"\n+      - name: \"mcore\"\n+        description: \"Affects the mcore target\"\n+        match:\n+          file: \"config/mcore/\"\n+      - name: \"microblaze\"\n+        description: \"Affects the microblaze target\"\n+        match:\n+          file: \"config/microblaze/\"\n+      - name: \"mips\"\n+        description: \"Affects the mips target\"\n+        match:\n+          file: \"config/mips/\"\n+      - name: \"mmix\"\n+        description: \"Affects the mmix target\"\n+        match:\n+          file: \"config/mmix/\"\n+      - name: \"mn10300\"\n+        description: \"Affects the mn1030 target\"\n+        match:\n+          file: \"config/mn10300/\"\n+      - name: \"moxie\"\n+        description: \"Affects the moxie target\"\n+        match:\n+          file: \"config/moxie/\"\n+      - name: \"msp430\"\n+        description: \"Affects the msp430 target\"\n+        match:\n+          file: \"config/msp430/\"\n+      - name: \"nds32\"\n+        description: \"Affects the nds32 target\"\n+        match:\n+          file: \"config/nds32/\"\n+      - name: \"nvptx\"\n+        description: \"Affects the nvptx target\"\n+        match:\n+          file: \"config/nvptx/\"\n+      - name: \"or1k\"\n+        description: \"Affects the or1k target\"\n+        match:\n+          file: \"config/or1k/\"\n+      - name: \"pa\"\n+        description: \"Affects the pa target\"\n+        match:\n+          file: \"config/pa/\"\n+      - name: \"pdp11\"\n+        description: \"Affects the pdp1 target\"\n+        match:\n+          file: \"config/pdp11/\"\n+      - name: \"pru\"\n+        description: \"Affects the pru target\"\n+        match:\n+          file: \"config/pru/\"\n+      - name: \"riscv\"\n+        description: \"Affects the riscv target\"\n+        match:\n+          file: \"config/riscv/\"\n+      - name: \"rl78\"\n+        description: \"Affects the rl78 target\"\n+        match:\n+          file: \"config/rl78/\"\n+      - name: \"rs6000\"\n+        description: \"Affects the rs6000 target\"\n+        match:\n+          file: \"config/rs6000/\"\n+      - name: \"rx\"\n+        description: \"Affects the rx target\"\n+        match:\n+          file: \"config/rx/\"\n+      - name: \"s390\"\n+        description: \"Affects the s390 target\"\n+        match:\n+          file: \"config/s390/\"\n+      - name: \"sh\"\n+        description: \"Affects the sh target\"\n+        match:\n+          file: \"config/sh/\"\n+      - name: \"sparc\"\n+        description: \"Affects the sparc target\"\n+        match:\n+          file: \"config/sparc/\"\n+      - name: \"stormy16\"\n+        description: \"Affects the stormy16 target\"\n+        match:\n+          file: \"config/x?stormy16/\"\n+      - name: \"v850\"\n+        description: \"Affects the v850 target\"\n+        match:\n+          file: \"config/v850/\"\n+      - name: \"vax\"\n+        description: \"Affects the vax target\"\n+        match:\n+          file: \"config/vax/\"\n+      - name: \"visium\"\n+        description: \"Affects the visium target\"\n+        match:\n+          file: \"config/visium/\"\n+      - name: \"xtensa\"\n+        description: \"Affects the xtensa target\"\n+        match:\n+          file: \"config/xtensa/\"\n+  # Labels specific to an object file format\n+  - group: \"Obj\"\n+    exclusive: false\n+    color: \"b0ffb0\"\n+    match_defaults:\n+      class: \"file\"\n+    labels:\n+      - name: \"coff\"\n+        description: \"Target independent code related to COFF object format\"\n+        match:\n+          file: \"*coff*\"\n+          priority: 2\n+      - name: \"elf\"\n+        description: \"Target independent code related to COFF object format\"\n+        match:\n+          file: \"*elf*\"\n+          priority: 2\n+      - name: \"pe\"\n+        description: \"Target independent code related to PE-COFF object format\"\n+        # No auto-match entry.\n+  # Labels relating to a specific OS\n+  - group: \"OS\"\n+    exclusive: false\n+    color: \"b0fff9\"\n+    match_defaults:\n+      class: \"file\"\n+    labels:\n+      - name: \"aix\"\n+        description: \"Affects AIX OS\"\n+        match:\n+          file: \"rs6000/*aix*\"\n+      - name: \"android\"\n+        description: \"Affects Android OS\"\n+        match:\n+          file: \"*android*\"\n+      - name: \"cygwin\"\n+        description: \"Affects cywin or mingw OSes\"\n+        match:\n+          file: \"(config/mingw/|*(cyqwin|mingw)*)\"\n+      - name: \"darwin\"\n+        description: \"Affects Darwin OS\"\n+        match:\n+          file: \"*darwin*\"\n+      - name: \"dragonfly\"\n+        description: \"Affects Dragonfly OS\"\n+        match:\n+          file: \"*dragonfly*\"\n+      - name: \"freebsd\"\n+        description: \"Affects FreeBSD OS\"\n+        match:\n+          file: \"*freebsd*\"\n+      - name: \"hpux\"\n+        description: \"Affects HP-UX OS\"\n+        match:\n+          file: \"*hpux*\"\n+      - name: \"hurd\"\n+        description: \"Affects GNU Hurd OS\"\n+        match:\n+          file: \"*hurd*\"\n+      - name: \"linux\"\n+        description: \"Affects generic Linux OS\"\n+        match:\n+          file: \"*linux*\"\n+          priority: 2\n+      - name: \"netbsd\"\n+        description: \"Affects NetBSD OS\"\n+        match:\n+          file: \"*netbsd*\"\n+      - name: \"openbsd\"\n+        description: \"Affects OpenBSD OS\"\n+        match:\n+          file: \"*openbsd*\"\n+      - name: \"rtems\"\n+        description: \"Affects RTEMS OS\"\n+        match:\n+          file: \"*rtems*\"\n+      - name: \"solaris\"\n+        description: \"Affects Solaris OS\"\n+        match:\n+          file: \"(sol2*|*solaris*)\"\n+      - name: \"vms\"\n+        description: \"Affects VMS OS\"\n+        match:\n+          file: \"(*[^a-z])?vms*\"\n+      - name: \"vxworks\"\n+        description: \"Affects VxWorks\"\n+        match:\n+          file: \"(config/vxworks/|*vxworks*)\"\n+      - name: \"windows\"\n+        description: \"Affects Windows OS\"\n+        match:\n+          file: \"*windows*\"\n+  # Labels relating to compiler mid-end\n+  - group: \"Midend\"\n+    exclusive: false\n+    color: \"207de5\"\n+    match_defaults:\n+      class: \"file\"\n+    labels:\n+      - name: \"diagnostics\"\n+        description: \"Diagnostics framework\"\n+        match:\n+          file: \"^/gcc/(diagnostics/|text-art/|*diagnostic*|*sarif*)\"\n+      - name: \"rtl\"\n+        description: \"General RTL code\"\n+        match:\n+          file: \"^/gcc/*.(cc|c|h)\"\n+          priority: 3\n+      - name: \"reg-alloc\"\n+        description: \"Register allocation code\"\n+        match:\n+          file: \"^/gcc/*(ira|lra)*\"\n+      - name: \"tree\"\n+        description: \"General tree/gimple code\"\n+        match:\n+          file: \"^/gcc/*tree*\"\n+          priority: 2\n+      - name: \"vect\"\n+        description: \"Vectorization\"\n+        match:\n+          file: \"^/gcc/*vect*\"\n+      - name: \"cfg\"\n+        description: \"Control Flow Graph framework\"\n+        match:\n+          file: \"^/gcc/*cfg*\"\n+      - name: \"ggc\"\n+        description: \"Garbage collection\"\n+        match:\n+          file: \"^/gcc/*ggc*\"\n+      - name: \"gen\"\n+        description: \"Generator programs, eg genattr\"\n+        match:\n+          file: \"^/gcc/gen*.(cc|h)\"\n+      - name: \"ipa\"\n+        description: \"Inter Procedural Analysis framework\"\n+        match:\n+          file: \"^/gcc/ipa*\"\n+      - name: \"misc\"\n+        description: \"Miscellaneous files that doesn't fit anything else\"\n+        match:\n+          file: \"^/gcc/*\"\n+          priority: 4\n+      - name: \"lto\"\n+        description: \"Link Time Optimizer code\"\n+        match:\n+          file: \"^/gcc/(lto/|*lto*)\"\n+      - name: \"jit\"\n+        description: \"JIT (Just-In-Time) code\"\n+        match:\n+          file: \"^/gcc/jit/\"\n+      - name: \"include\"\n+        description: \"Include headers and fixincludes\"\n+        match:\n+          file: \"^/(fixincludes|gcc/ginclude)/\"\n+      - name: \"dwarf\"\n+        description: \"Dwarf debug information\"\n+        match:\n+          file: \"^/gcc/**/*dwarf*\"\n+      - name: \"debug\"\n+        description: \"Non-dwarf debug support\"\n+        match:\n+          file: \"^/gcc/*ctf*\"\n+      - name: \"gimple\"\n+        description: \"General GIMPLE support\"\n+        match:\n+          file: \"^/gcc/*gimple*\"\n+      - name: \"gcse\"\n+        description: \"RTL GCSE\"\n+        match:\n+          file: \"^/gcc/*gcse*\"\n+      - name: \"jump\"\n+        description: \"Jump and branch optimizations\"\n+        match:\n+          file: \"^/gcc/*jump*\"\n+      - name: \"i18n\"\n+        description: \"Internationalization and Localization\"\n+        match:\n+          file: \"^/gcc/(po/|intl.*)\"\n+      - name: \"gcov\"\n+        description: \"GCOV code coverage support\"\n+        match:\n+          file: \"^/gcc/gcov*\"\n+      - name: \"opts\"\n+        description: \"Option framework\"\n+        match:\n+          file: \"^/gcc/(opt*.awk|*.opt|opt[-s]*)\"\n+      - name: \"ranger\"\n+        description: \"Value range framework\"\n+        match:\n+          file: \"^/gcc/*range*\"\n+      - name: \"rtl-ssa\"\n+        description: \"RTL SSA framework\"\n+        match:\n+          file: \"^/gcc/rtl-ssa/\"\n+      - name: \"tree-ssa\"\n+        description: \"Tree SSA framework\"\n+        match:\n+          file: \"^/gcc/(tree|gimple)-ssa*\"\n+      - name: \"autofdo\"\n+        description: \"AutoFDO framework\"\n+        match:\n+          file: \"^/gcc/auto-profile*\"\n+      - name: \"combine\"\n+        description: \"Instruction Combiner\"\n+        match:\n+          file: \"^/gcc/combine*\"\n+      - name: \"reload\"\n+        description: \"Legacy reload pass (obsolete)\"\n+        match:\n+          file: \"^/gcc/reload*\"\n+      - name: \"pair-fusion\"\n+        description: \"Pair Fusion framework\"\n+        match:\n+          file: \"^/gcc/pair-fusion*\"\n+      - name: \"ivopts\"\n+        description: \"Loop IVopt framework\"\n+        match:\n+          file: \"^/gcc/*loop-iv*\"\n+      - name: \"loop\"\n+        description: \"Loop optimizations\"\n+        match:\n+          file: \"^/gcc/*loop*\"\n+      - name: \"openacc\"\n+        description: \"OpenACC framework\"\n+        # No auto-match entry\n+      - name: \"openmp\"\n+        description: \"OpenMP framework\"\n+        match:\n+          file: \"^/gcc/omp*\"\n+      - name: \"analyzer\"\n+        description: \"Static analyzer\"\n+        match:\n+          file: \"^/gcc/analyzer/\"\n+  # Labels relating to language frontends\n+  - group: \"Frontend\"\n+    exclusive: false\n+    color: \"0052cc\"\n+    match_defaults:\n+      class: \"file\"\n+    labels:\n+      - name: \"ada\"\n+        description: \"The Ada frontend\"\n+        match:\n+          file: \"^/gcc/ada/\"\n+      - name: \"algol68\"\n+        description: \"The Algol68 frontend\"\n+        match:\n+          file: \"^/gcc/algol68/\"\n+      - name: \"c\"\n+        description: \"The C frontend\"\n+        match:\n+          file: \"^/gcc/c(|-family)/\"\n+      - name: \"c++\"\n+        description: \"The C++ frontend\"\n+        match:\n+          file: \"^/gcc/c(p|-family)/\"\n+      - name: \"cobol\"\n+        description: \"The COBOL frontend\"\n+        match:\n+          file: \"^/gcc/cobol/\"\n+      - name: \"d\"\n+        description: \"The D frontend\"\n+        match:\n+          file: \"^/gcc/d/\"\n+      - name: \"fortran\"\n+        description: \"The Fortran frontend\"\n+        match:\n+          file: \"^/gcc/fortran/\"\n+      - name: \"go\"\n+        description: \"The Go frontend\"\n+        match:\n+          file: \"^/gcc/(go/|godump*)\"\n+      - name: \"m2\"\n+        description: \"The Modula-2 frontend\"\n+        match:\n+          file: \"^/gcc/m2/\"\n+      - name: \"objc\"\n+        description: \"The Objective-C/-C++ frontends\"\n+        match:\n+          file: \"^/gcc/objcp?/\"\n+      - name: \"rust\"\n+        description: \"The Rust frontend\"\n+        match:\n+          file: \"^/gcc/rust/\"\n+  # Labels relating to testsuites (probably incomplete)\n+  - group: \"Tests\"\n+    exclusive: false\n+    color: \"c544ff\"\n+    match_defaults:\n+      class: \"file\"\n+    labels:\n+      - name: \"framework\"\n+        description: \"Changes to the test framework (testsuite/lib)\"\n+        match:\n+          file: \"testsuite/lib/\"\n+      - name: \"torture\"\n+        description: \"Changes to legacy torture tests\"\n+        match:\n+          file: \"^/gcc/testsuite/*-torture/\"\n+      - name: \"target\"\n+        description: \"Changes to target-specific tests (use target/* as well)\"\n+        match:\n+          file: \"^/gcc/testsuite/*.target/\"\n+      - name: \"lang\"\n+        description: \"Changes to language-specific tests\"\n+        match:\n+          file: \"^/gcc/testsuite/(gcc|gdc|gfortran|g++|obj|go|cobol|gnat|ada|c-c++|gm2|rust)*/\"\n+      - name: \"lib\"\n+        description: \"Changes to top-level library tests (use Library/* as well)\"\n+        match:\n+          file: \"^/lib*/**/testsuite/\"\n+      - name: \"jit\"\n+        description: \"Changes to GCC's jit tests\"\n+        match:\n+          file: \"^/gcc/testsuite/jit.dg/\"\n+      - name: \"selftest\"\n+        description: \"Changes to GCC's self-tests\"\n+        match:\n+          file: \"^/gcc/testsuite/selftests/\"\n+      - name: \"diagnostics\"\n+        description: \"Changes to GCC's diagnostic framework tests\"\n+        match:\n+          file: \"^/gcc/testsuite/libgdiagnostics.dg/\"\n+      - name: \"sarif\"\n+        description: \"Changes to GCC's sarif tests\"\n+        match:\n+          file: \"^/gcc/testsuite/sarif-replay.dg/\"\n+\n+  # # Forge status labels\n+  # These have been removed for now.  It's not clear how useful\n+  # these would be, given that we may have more than one runner\n+  #\n+  # # Labels for runners (exclusive)\n+  # - group: \"Runners\"\n+  #   exclusive: true\n+  #   color: \"f6c6c7\"\n+  #   match_defaults:\n+  #     class: \"none\"\n+  #   labels:\n+  #     - name: \"pending\"\n+  #       description: \"Runner has started, but results not yet available\"\n+  #     - name: \"unresolved\"\n+  #       description: \"Runner failed for an unknown reason\"\n+  #     - name: \"red\"\n+  #       description: \"Check failed with errors, code not fit for committing\"\n+  #     - name: \"amber\"\n+  #       description: \"Check failed with warnings, manually inspect results\"\n+  #     - name: \"green\"\n+  #       description: \"Checks passed\"\n+  - group: \"Reviewed\"\n+    exclusive: true\n+    color: \"616161\"\n+    match_defaults:\n+      class: \"file\"\n+    labels:\n+      - name: Confirmed\n+        description: \"Issue has been confirmed\"\ndiff --git a/contrib/forge/update-labels.py b/contrib/forge/update-labels.py\nnew file mode 100755\nindex 000000000000..b8e81b617e43\n--- /dev/null\n+++ b/contrib/forge/update-labels.py\n@@ -0,0 +1,151 @@\n+#! /usr/bin/env python3\n+# Update the list of labels on a Forgejo instance\n+\n+# Copyright (C) 2026 Free Software Foundation, Inc.\n+#\n+# This file is part of GCC.\n+#\n+# GCC is free software; you can redistribute it and/or modify it under\n+# the terms of the GNU General Public License as published by the Free\n+# Software Foundation; either version 3, or (at your option) any later\n+# version.\n+#\n+# GCC is distributed in the hope that it will be useful, but WITHOUT ANY\n+# WARRANTY; without even the implied warranty of MERCHANTABILITY or\n+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n+# for more details.\n+#\n+# You should have received a copy of the GNU General Public License\n+# along with GCC; see the file COPYING3.  If not see\n+# <http://www.gnu.org/licenses/>.\n+\n+# Variables needed by the script.  Can be overridden by setting the\n+# same name in the environment\n+\n+PROJECT = \"gcc\"\n+REPO    = \"gcc-test\"\n+FORGE  = \"https://forge.sourceware.org/api/v1\"\n+\n+APIKEY  = None\n+\n+import os, sys, forgelabels, urllib.request, json, getpass\n+\n+def setup():\n+    global PROJECT, REPO, FORGE, APIKEY\n+    PROJECT = os.getenv(\"PROJECT\", PROJECT)\n+    REPO = os.getenv(\"REPO\", REPO)\n+    FORGE = os.getenv(\"FORGE\", FORGE)\n+    APIKEY = getpass.getpass(prompt=\"API key: \")\n+    print (f\"Accessing {FORGE}/{PROJECT}/{REPO}.\")\n+\n+def read_existing():\n+    global FORGE, PROJECT, REPO\n+    try:\n+        url = f\"{FORGE}/repos/{PROJECT}/{REPO}/labels\"\n+        reply = urllib.request.urlopen(url)\n+        labels_list = json.loads(reply.read())\n+    except Exception as e:\n+        print (f\"Error reading label data: {e}\")\n+        sys.exit (1)\n+    return labels_list\n+\n+def add_label(l):\n+    global FORGE, PROJECT, REPO, APIKEY\n+    payload = {'name': l.full_name,\n+               'color': l.color(),\n+               'exclusive': l.group.exclusive,\n+               'is_archived': False}\n+    if l.desc != None:\n+        payload['description'] = l.desc\n+    headers = {'Authorization': f\"token {APIKEY}\",\n+               'accept': \"application/json\",\n+               'Content-Type': \"application/json\"} \n+    try:\n+        url = f\"{FORGE}/repos/{PROJECT}/{REPO}/labels\"\n+        payload = json.dumps (payload).encode(\"utf-8\")\n+        request = urllib.request.Request (url, data = payload,\n+                                          headers = headers,\n+                                          method = 'POST')\n+        reply = urllib.request.urlopen(request)\n+    except Exception as e:\n+        print (f\"Error writing label data: {e}\")\n+        sys.exit (1)\n+    print (f\"Success: add {l.full_name}\")\n+\n+def modify_label(o, l):\n+    global FORGE, PROJECT, REPO, APIKEY\n+    payload = {'name': l.full_name,\n+               'color': l.color(),\n+               'exclusive': l.group.exclusive,\n+               'is_archived': False}\n+    if l.desc != None:\n+        payload['description'] = l.desc\n+    headers = {'Authorization': f\"token {APIKEY}\",\n+               'accept': \"application/json\",\n+               'Content-Type': \"application/json\"} \n+    try:\n+        url = f\"{FORGE}/repos/{PROJECT}/{REPO}/labels/{o['id']}\"\n+        payload = json.dumps (payload).encode(\"utf-8\")\n+        request = urllib.request.Request (url, data = payload,\n+                                          headers = headers,\n+                                          method = 'PATCH')\n+        reply = urllib.request.urlopen(request)\n+    except Exception as e:\n+        print (f\"Error writing label data: {e}\")\n+        sys.exit (1)\n+    print (f\"Success: modify {l.full_name}\")\n+\n+def archive_label(o):\n+    global FORGE, PROJECT, REPO, APIKEY\n+    payload = {'name': o['name'],\n+               'is_archived': True}\n+    headers = {'Authorization': f\"token {APIKEY}\",\n+               'accept': \"application/json\",\n+               'Content-Type': \"application/json\"} \n+    try:\n+        url = f\"{FORGE}/repos/{PROJECT}/{REPO}/labels/{o['id']}\"\n+        payload = json.dumps (payload).encode(\"utf-8\")\n+        request = urllib.request.Request (url, data = payload,\n+                                          headers = headers,\n+                                          method = 'PATCH')\n+        reply = urllib.request.urlopen(request)\n+    except Exception as e:\n+        print (f\"Error writing label data: {e}\")\n+        sys.exit (1)\n+    print (f\"Success: archive {o['name']}\")\n+\n+def main():\n+    setup()\n+    groups = forgelabels.load()\n+    oldlabels = read_existing()\n+    toadd = []\n+    tochange = []\n+\n+    for g in groups:\n+        for l in g.labels:\n+            matched = False\n+            for o in oldlabels:\n+                if o['name'] == l.full_name:\n+                    if (o['is_archived']\n+                        or o['color'] != l.color()\n+                        or o['exclusive'] != l.group.exclusive\n+                        or o['description'] != l.desc):\n+                        tochange.append((o, l))\n+                    matched = True\n+                    o['matched'] = True\n+                    break\n+            if not matched:\n+                toadd.append(l)\n+    for o in oldlabels:\n+        if not 'matched' in o and not o['is_archived']:\n+            archive_label(o)\n+            print (f\"To archive: {o['name']}\")\n+    for o, n in tochange:\n+        modify_label (o, n)\n+    for l in toadd:\n+        add_label (l)\n+\n+if __name__ == \"__main__\":\n+    main()\n+\n+    \n",
    "prefixes": [
        "v1",
        "1/1"
    ]
}