[v2,4/6] maintainer_utils: support inactive_DCO

Message ID bmm.hlw1gcuuvc.gcc.gcc.rearnsha.222.2.4@forge-stage.sourceware.org
State New
Headers
Series maintainer_utils.py: general cleanups |

Commit Message

Richard Earnshaw via Sourceware Forge Sept. 1, 2026, 2:36 p.m. UTC
  From: Richard Earnshaw <rearnsha@arm.com>

I've already seen cases of people removing a DCO entry when they change
email addresses.  We don't want that to happen, but it's difficult to
enforce this via the tools without reading history of the YAML data.

Make it a bit more obvious what to do with historical DCO entries by
adding an inactive_DCO entry that mirrors the treatment of inactive_email.
We don't (at present) use the additional information, but at some time
in the future the forge might use this to detect submissions with
a retired DCO address.

ChangeLog:

	* MAINTAINERS.yml: Convert an entry to use inactive_DCO.

contrib/ChangeLog:

	* maintainer_utils.py (maintainer_schema): Allow inactive_DCO
	for retired DCO addresses.
	(_check_dco): Validate inactive_DCO entries as well.
	(validate): Check inactive_DCO data.
	* gen-MAINTAINERS.py (format_output): Combine inactive_DCO with
	DCO entries.
---
 MAINTAINERS.yml             |  1 +
 contrib/gen-MAINTAINERS.py  |  2 +-
 contrib/maintainer_utils.py | 30 ++++++++++++++++++++++++------
 3 files changed, 26 insertions(+), 7 deletions(-)
  

Patch

diff --git a/MAINTAINERS.yml b/MAINTAINERS.yml
index b48c753ede972..64b185dc74bff 100644
--- a/MAINTAINERS.yml
+++ b/MAINTAINERS.yml
@@ -4603,6 +4603,7 @@  users:
   account: pep
   DCO:
   - pierre.emmanuel.patry@opensrcsec.com
+  inactive_DCO:
   - pierre-emmanuel.patry@embecosm.com
 - sn: Pavenis
   cn: Andris Pavenis
diff --git a/contrib/gen-MAINTAINERS.py b/contrib/gen-MAINTAINERS.py
index 4fcc4dcfc8527..ae9e12bb0d1ae 100755
--- a/contrib/gen-MAINTAINERS.py
+++ b/contrib/gen-MAINTAINERS.py
@@ -245,7 +245,7 @@  def format_output(outfile, data):
             subclass = section['filter'].get('subclass')
             for u in all_users:
                 if role == 'DCO':
-                    for email in u.get('DCO', []):
+                    for email in u.get('DCO', []) + u.get('inactive_DCO', []):
                         d = {
                             'email': email,
                             'account': u.get('account', '-'),
diff --git a/contrib/maintainer_utils.py b/contrib/maintainer_utils.py
index 8199fd588758f..13861a0401c47 100755
--- a/contrib/maintainer_utils.py
+++ b/contrib/maintainer_utils.py
@@ -75,6 +75,14 @@  maintainer_schema = {
                         },
                         "minItems": 1,
                     },
+                    'inactive_DCO': {
+                        'type': 'array',
+                        'items': {
+                            'type': 'string',
+                            'format': 'email',
+                        },
+                        "minItems": 1,
+                    },
                     'roles': {
                         'type': 'array',
                         'items': {
@@ -143,6 +151,7 @@  maintainer_schema = {
                 'anyOf': [
                     {'required': ['roles']},
                     {'required': ['DCO']},
+                    {'required': ['inactive_DCO']},
                 ],
             },
         },
@@ -247,10 +256,18 @@  def _check_schema(data):
 def _check_dco(user):
     # An email addrss in a DCO entry must also be listed in either the
     # active emails list, or the inactive_emails list.
-    emails = set(user['email'] + user.get('inactive_email', []))
-    for dco in user['DCO']:
+    emails = user['email']
+    for dco in user.get('DCO', []):
+        if dco not in emails:
+            _error(f"User: {user['cn']} DCO {dco} not listed in emails")
+    emails = user.get('inactive_email', [])
+    for dco in user.get('inactive_DCO', []):
         if dco not in emails:
-            _error(f"User: {user['cn']} DCO {dco} not listed in other emails")
+            _error(
+                f"User: {user['cn']} inactive_DCO {dco} not listed in inactive_emails"
+            )
+        if dco in user.get('DCO', []):
+            _error(f"User: {user['cn']} inactive_DCO {dco} also listed in DCO")
 
 
 def validate(data):
@@ -263,10 +280,11 @@  def validate(data):
     # subsystems list; Maintainer entires must also have a class entry, though
     # that is optional for Reviewers.
     for u in data['users']:
-        if 'DCO' in u:
+        if 'DCO' in u or 'inactive_DCO' in u:
             _check_dco(u)
-        # The schema ensures that at least one of 'DCO' or 'roles'
-        # exists, so if roles is missing, we're done.
+        # The schema ensures that at least one of 'DCO',
+        # 'inactive_DCO' or 'roles' exists, so if roles is missing,
+        # we're done.
         if 'roles' not in u:
             continue
         # Users with the 'BZ' role should not have any other roles; we