Openembedded Core Discussions
 help / color / mirror / Atom feed
* [PATCH 1/2] devtool: upgrade: write changelog metadata as JSON sidecar
@ 2026-09-18 12:01 daniel.turull
  2026-09-18 12:01 ` [PATCH 2/2] devtool: upgrade: clean up changelog content for commit messages daniel.turull
  0 siblings, 1 reply; 2+ messages in thread
From: daniel.turull @ 2026-09-18 12:01 UTC (permalink / raw)
  To: openembedded-core; +Cc: Daniel Turull

From: Daniel Turull <daniel.turull@ericsson.com>

Add changelogs/<pn>.json alongside the existing changelogs/<pn>.txt,
to include metadata. This makes the upgrade/changelog metadata
machine-readable without having to parse it out of the .txt file.

The .txt file no longer has the 'Changelog for ...'/'Source: ...'
header lines, now containing just the changelog body; that
information moved to the JSON file instead. devtool reset now cleans
up both files.

AI-Generated: Uses Kiro with Claude-sonnet-5
Signed-off-by: Daniel Turull <daniel.turull@ericsson.com>
---
 .../python3-guessing-game_git.bb.changelog    |  2 --
 .../devtool-upgrade-test1_1.5.3.bb.changelog  |  3 ---
 .../devtool-upgrade-test2_git.bb.changelog    |  2 --
 .../devtool-upgrade-test3_1.5.3.bb.changelog  |  3 ---
 .../devtool-upgrade-test4_1.5.3.bb.changelog  |  3 ---
 .../devtool-upgrade-test5_git.bb.changelog    |  2 --
 meta/lib/oeqa/selftest/cases/devtool.py       | 17 +++++++++++++--
 scripts/lib/devtool/standard.py               |  9 +++++---
 scripts/lib/devtool/upgrade.py                | 21 +++++++++++++++----
 9 files changed, 38 insertions(+), 24 deletions(-)

diff --git a/meta-selftest/recipes-devtools/python/python3-guessing-game_git.bb.changelog b/meta-selftest/recipes-devtools/python/python3-guessing-game_git.bb.changelog
index 571220b2a4..ef0052160b 100644
--- a/meta-selftest/recipes-devtools/python/python3-guessing-game_git.bb.changelog
+++ b/meta-selftest/recipes-devtools/python/python3-guessing-game_git.bb.changelog
@@ -1,3 +1 @@
-Changelog for python3-guessing-game: 0.1.0 -> 0.2.0
-
 40cf004 Sync with maturin tutorial source
diff --git a/meta-selftest/recipes-test/devtool/devtool-upgrade-test1_1.5.3.bb.changelog b/meta-selftest/recipes-test/devtool/devtool-upgrade-test1_1.5.3.bb.changelog
index a37f796a0d..15d7baeeb4 100644
--- a/meta-selftest/recipes-test/devtool/devtool-upgrade-test1_1.5.3.bb.changelog
+++ b/meta-selftest/recipes-test/devtool/devtool-upgrade-test1_1.5.3.bb.changelog
@@ -1,6 +1,3 @@
-Changelog for devtool-upgrade-test1: 1.5.3 -> 1.6.0
-Source: doc/NEWS
-
 1.6.0 - 15 March 2015
   - fix lstat64 support when unavailable - separate patches supplied by
     Ganael Laplanche and Peter Korsgaard
diff --git a/meta-selftest/recipes-test/devtool/devtool-upgrade-test2_git.bb.changelog b/meta-selftest/recipes-test/devtool/devtool-upgrade-test2_git.bb.changelog
index b7f0019d56..ac133c483f 100644
--- a/meta-selftest/recipes-test/devtool/devtool-upgrade-test2_git.bb.changelog
+++ b/meta-selftest/recipes-test/devtool/devtool-upgrade-test2_git.bb.changelog
@@ -1,3 +1 @@
-Changelog for devtool-upgrade-test2: 0.1+git -> 0.1+git
-
 6cc6077 dbus-wait.c: Fix typo
diff --git a/meta-selftest/recipes-test/devtool/devtool-upgrade-test3_1.5.3.bb.changelog b/meta-selftest/recipes-test/devtool/devtool-upgrade-test3_1.5.3.bb.changelog
index aaab809736..15d7baeeb4 100644
--- a/meta-selftest/recipes-test/devtool/devtool-upgrade-test3_1.5.3.bb.changelog
+++ b/meta-selftest/recipes-test/devtool/devtool-upgrade-test3_1.5.3.bb.changelog
@@ -1,6 +1,3 @@
-Changelog for devtool-upgrade-test3: 1.5.3 -> 1.6.0
-Source: doc/NEWS
-
 1.6.0 - 15 March 2015
   - fix lstat64 support when unavailable - separate patches supplied by
     Ganael Laplanche and Peter Korsgaard
diff --git a/meta-selftest/recipes-test/devtool/devtool-upgrade-test4_1.5.3.bb.changelog b/meta-selftest/recipes-test/devtool/devtool-upgrade-test4_1.5.3.bb.changelog
index 0ce6547c77..15d7baeeb4 100644
--- a/meta-selftest/recipes-test/devtool/devtool-upgrade-test4_1.5.3.bb.changelog
+++ b/meta-selftest/recipes-test/devtool/devtool-upgrade-test4_1.5.3.bb.changelog
@@ -1,6 +1,3 @@
-Changelog for devtool-upgrade-test4: 1.5.3 -> 1.6.0
-Source: doc/NEWS
-
 1.6.0 - 15 March 2015
   - fix lstat64 support when unavailable - separate patches supplied by
     Ganael Laplanche and Peter Korsgaard
diff --git a/meta-selftest/recipes-test/devtool/devtool-upgrade-test5_git.bb.changelog b/meta-selftest/recipes-test/devtool/devtool-upgrade-test5_git.bb.changelog
index 7c5ecf3505..8077da3e21 100644
--- a/meta-selftest/recipes-test/devtool/devtool-upgrade-test5_git.bb.changelog
+++ b/meta-selftest/recipes-test/devtool/devtool-upgrade-test5_git.bb.changelog
@@ -1,3 +1 @@
-Changelog for devtool-upgrade-test5: 0.1+git -> 0.1+git
-
 0a60d6a Add dummy commit on tip for testing
diff --git a/meta/lib/oeqa/selftest/cases/devtool.py b/meta/lib/oeqa/selftest/cases/devtool.py
index 84e020cd3d..dda59a3459 100644
--- a/meta/lib/oeqa/selftest/cases/devtool.py
+++ b/meta/lib/oeqa/selftest/cases/devtool.py
@@ -2337,21 +2337,33 @@ class DevtoolUpgradeTests(DevtoolBase):
         except:
             self.skip("Git user.name and user.email must be set")
 
-    def _check_changelog(self, recipe, oldrecipefile):
+    def _check_changelog(self, recipe, oldrecipefile, old_ver=None, new_ver=None):
         """Compare extracted changelog against reference data."""
         changelog_ref = oldrecipefile + '.changelog'
         self.assertExists(changelog_ref, 'Changelog reference file must exist for %s' % recipe)
         changelog_file = os.path.join(self.workspacedir, 'changelogs', '%s.txt' % recipe)
+        metadata_file = os.path.join(self.workspacedir, 'changelogs', '%s.json' % recipe)
         with open(changelog_ref, 'r') as f:
             expected = f.read()
         if not expected:
             self.assertNotExists(changelog_file,
                 'Changelog file should not exist when reference is empty')
+            self.assertNotExists(metadata_file,
+                'Changelog metadata file should not exist when reference is empty')
         else:
             self.assertExists(changelog_file, 'Changelog file should exist after upgrade')
             with open(changelog_file, 'r') as f:
                 actual = f.read()
             self.assertEqual(expected, actual)
+            self.assertExists(metadata_file, 'Changelog metadata file should exist after upgrade')
+            with open(metadata_file, 'r') as f:
+                metadata = json.load(f)
+            self.assertEqual(metadata.get('package'), recipe)
+            if old_ver:
+                self.assertEqual(metadata.get('old_version'), old_ver)
+            if new_ver:
+                self.assertEqual(metadata.get('new_version'), new_ver)
+            self.assertEqual(metadata.get('changelog_file'), '%s.txt' % recipe)
 
     def test_devtool_upgrade(self):
         # Check preconditions
@@ -2364,6 +2376,7 @@ class DevtoolUpgradeTests(DevtoolBase):
             self.assertIn(param, result.output)
         # For the moment, we are using a real recipe.
         recipe = 'devtool-upgrade-test1'
+        old_version = '1.5.3'
         version = '1.6.0'
         oldrecipefile = get_bb_var('FILE', recipe)
         tempdir = tempfile.mkdtemp(prefix='devtoolqa')
@@ -2392,7 +2405,7 @@ class DevtoolUpgradeTests(DevtoolBase):
             newlines = f.readlines()
         self.assertEqual(desiredlines, newlines)
         # Check changelog
-        self._check_changelog(recipe, oldrecipefile)
+        self._check_changelog(recipe, oldrecipefile, old_version, version)
         # Check devtool reset recipe
         result = runCmd('devtool reset %s -n' % recipe)
         result = runCmd('devtool status')
diff --git a/scripts/lib/devtool/standard.py b/scripts/lib/devtool/standard.py
index ac9e7cd61a..0d933e68b1 100644
--- a/scripts/lib/devtool/standard.py
+++ b/scripts/lib/devtool/standard.py
@@ -2074,11 +2074,14 @@ def _reset(recipes, no_clean, remove_work, config, basepath, workspace):
 
         # Clean up changelog if present
         changelog_file = os.path.join(config.workspace_path, 'changelogs', '%s.txt' % pn)
+        metadata_file = os.path.join(config.workspace_path, 'changelogs', '%s.json' % pn)
         if os.path.exists(changelog_file):
             os.remove(changelog_file)
-            changelog_dir = os.path.dirname(changelog_file)
-            if not os.listdir(changelog_dir):
-                os.rmdir(changelog_dir)
+        if os.path.exists(metadata_file):
+            os.remove(metadata_file)
+        changelog_dir = os.path.join(config.workspace_path, 'changelogs')
+        if os.path.exists(changelog_dir) and not os.listdir(changelog_dir):
+            os.rmdir(changelog_dir)
 
 def reset(args, config, basepath, workspace):
     """Entry point for the devtool 'reset' subcommand"""
diff --git a/scripts/lib/devtool/upgrade.py b/scripts/lib/devtool/upgrade.py
index 58165541f6..cdc85fe7ae 100644
--- a/scripts/lib/devtool/upgrade.py
+++ b/scripts/lib/devtool/upgrade.py
@@ -9,6 +9,7 @@
 import os
 import sys
 import re
+import json
 import shlex
 import shutil
 import subprocess
@@ -730,13 +731,23 @@ def _extract_changelog(srctree, pn, old_ver, new_ver, old_tag, new_tag, workspac
     bb.utils.mkdirhier(changelog_dir)
     changelog_path = os.path.join(changelog_dir, '%s.txt' % pn)
     with open(changelog_path, 'w') as f:
-        f.write('Changelog for %s: %s -> %s\n' % (pn, old_ver, new_ver))
-        if changelog_fname:
-            f.write('Source: %s\n' % changelog_fname)
-        f.write('\n')
         f.write(changelog_content)
         f.write('\n')
 
+    # Metadata sidecar file: keeps upgrade/changelog details machine-readable
+    # while the changelog text itself stays in the .txt file.
+    metadata = {
+        'package': pn,
+        'old_version': old_ver,
+        'new_version': new_ver,
+        'changelog_file': os.path.basename(changelog_path),
+        'changelog_source': changelog_fname.split(', ') if changelog_fname else None,
+    }
+    metadata_path = os.path.join(changelog_dir, '%s.json' % pn)
+    with open(metadata_path, 'w') as f:
+        json.dump(metadata, f, indent=4)
+        f.write('\n')
+
     return changelog_path
 
 def upgrade(args, config, basepath, workspace):
@@ -831,6 +842,8 @@ def upgrade(args, config, basepath, workspace):
                                             config.workspace_path, is_git)
         if changelog_file:
             logger.info('Changelog extracted to %s' % changelog_file)
+            metadata_file = os.path.join(os.path.dirname(changelog_file), '%s.json' % pn)
+            logger.info('Changelog metadata written to %s' % metadata_file)
 
         if license_diff:
             logger.info('License checksums have been updated in the new recipe; please refer to it for the difference between the old and the new license texts.')


^ permalink raw reply related	[flat|nested] 2+ messages in thread

* [PATCH 2/2] devtool: upgrade: clean up changelog content for commit messages
  2026-09-18 12:01 [PATCH 1/2] devtool: upgrade: write changelog metadata as JSON sidecar daniel.turull
@ 2026-09-18 12:01 ` daniel.turull
  0 siblings, 0 replies; 2+ messages in thread
From: daniel.turull @ 2026-09-18 12:01 UTC (permalink / raw)
  To: openembedded-core; +Cc: Daniel Turull

From: Daniel Turull <daniel.turull@ericsson.com>

Strip noise that has no value in a commit message:
- GitHub PR references: trailing "(#NNN)" and full pull/issue URLs.
- Commit hash prefixes from "git log --oneline"-style content,
  including the git-log fallback used when no changelog file exists.
- GNU ChangeLog noise: "YYYY-MM-DD  Name  <email>" entry headers, and
  "* file (func):" / "+ commit <hash>" bullets plus their wrapped
  continuation lines, down to the next blank line, keeping only the
  human-readable summary of each entry. Remaining tabs are stripped.
- NEWS-style "Changes in X.Y.Z, DATE" release headers and their "==="
  underline (libportal/glib-family projects).

Lines exceeding 80 chars are wrapped, preserving existing indentation.

AI-Generated: Uses Kiro with Claude Sonnet 5
Signed-off-by: Daniel Turull <daniel.turull@ericsson.com>
---
 .../python3-guessing-game_git.bb.changelog    |  2 +-
 .../devtool-upgrade-test2_git.bb.changelog    |  2 +-
 .../devtool-upgrade-test5_git.bb.changelog    |  2 +-
 scripts/lib/devtool/upgrade.py                | 63 ++++++++++++++++++-
 4 files changed, 65 insertions(+), 4 deletions(-)

diff --git a/meta-selftest/recipes-devtools/python/python3-guessing-game_git.bb.changelog b/meta-selftest/recipes-devtools/python/python3-guessing-game_git.bb.changelog
index ef0052160b..6c7bf9f713 100644
--- a/meta-selftest/recipes-devtools/python/python3-guessing-game_git.bb.changelog
+++ b/meta-selftest/recipes-devtools/python/python3-guessing-game_git.bb.changelog
@@ -1 +1 @@
-40cf004 Sync with maturin tutorial source
+Sync with maturin tutorial source
diff --git a/meta-selftest/recipes-test/devtool/devtool-upgrade-test2_git.bb.changelog b/meta-selftest/recipes-test/devtool/devtool-upgrade-test2_git.bb.changelog
index ac133c483f..4699b1e89e 100644
--- a/meta-selftest/recipes-test/devtool/devtool-upgrade-test2_git.bb.changelog
+++ b/meta-selftest/recipes-test/devtool/devtool-upgrade-test2_git.bb.changelog
@@ -1 +1 @@
-6cc6077 dbus-wait.c: Fix typo
+dbus-wait.c: Fix typo
diff --git a/meta-selftest/recipes-test/devtool/devtool-upgrade-test5_git.bb.changelog b/meta-selftest/recipes-test/devtool/devtool-upgrade-test5_git.bb.changelog
index 8077da3e21..3196cc13bd 100644
--- a/meta-selftest/recipes-test/devtool/devtool-upgrade-test5_git.bb.changelog
+++ b/meta-selftest/recipes-test/devtool/devtool-upgrade-test5_git.bb.changelog
@@ -1 +1 @@
-0a60d6a Add dummy commit on tip for testing
+Add dummy commit on tip for testing
diff --git a/scripts/lib/devtool/upgrade.py b/scripts/lib/devtool/upgrade.py
index cdc85fe7ae..ba7348664f 100644
--- a/scripts/lib/devtool/upgrade.py
+++ b/scripts/lib/devtool/upgrade.py
@@ -14,6 +14,7 @@ import shlex
 import shutil
 import subprocess
 import tempfile
+import textwrap
 import logging
 import argparse
 import scriptutils
@@ -634,6 +635,66 @@ def _diff_git_log_changelog(old_content, new_content):
     return '\n'.join(subjects) if subjects else None
 
 
+# GitHub PR references: trailing (#123) at end of line, or full URLs
+_GITHUB_PR_RE = re.compile(r'\s*\(#[0-9]+\)\s*$|\s*https?://github\.com/[^/]+/[^/]+/(pull|issues)/[0-9]+\s*')
+# Commit hash prefixes from git log --oneline: "abc1234 "
+_COMMIT_HASH_RE = re.compile(r'^[0-9a-f]{7,40}\s+')
+# A GNU ChangeLog entry: starts at either an entry header
+# ("2026-08-24  Werner Koch  <wk@gnupg.org>") or a technical bullet
+# ("* file.c (func): text" or "+ commit <hash>"), and extends through all
+# wrapped continuation lines up to (but not including) the next blank line.
+_GNU_CHANGELOG_ENTRY_RE = re.compile(
+    r'^(?:\d{4}-\d{2}-\d{2}\s+.+<.+@.+>|\s*(?:\*\s|\+ commit [0-9a-f]{7,40}).*)'
+    r'(?:\n(?!\s*$).*)*\n?',
+    re.MULTILINE)
+# NEWS-style release header + underline (glib/gtk family):
+# "Changes in 0.11.0, 2026-09-12\n===============================\n"
+_NEWS_RELEASE_HEADER_RE = re.compile(r'^Changes in .+,\s*\d{4}-\d{2}-\d{2}\s*\n=+\s*$', re.MULTILINE)
+
+def _join_single_line_paragraphs(text):
+    """Drop the blank line between two adjacent one-line paragraphs (each
+    surrounded by blank lines), so lines left behind by GNU ChangeLog entry
+    stripping read as one entry per line instead of double-spaced."""
+    paragraphs = text.split('\n\n')
+    out = [paragraphs[0]]
+    prev_is_single_line = '\n' not in paragraphs[0]
+    for para in paragraphs[1:]:
+        this_is_single_line = '\n' not in para
+        if prev_is_single_line and this_is_single_line:
+            out[-1] += '\n' + para
+        else:
+            out.append(para)
+        prev_is_single_line = this_is_single_line
+    return '\n\n'.join(out)
+
+
+def _cleanup_changelog(content):
+    """Strip GitHub PR refs, commit hashes, GNU ChangeLog entries (headers
+    and file/function bullets, plus their wrapped continuation lines) and
+    NEWS-style 'Changes in X.Y.Z, DATE' release headers with their
+    underline. Wrap lines over 80 chars, preserving indentation."""
+    content = _NEWS_RELEASE_HEADER_RE.sub('', content)
+    content = _GNU_CHANGELOG_ENTRY_RE.sub('', content)
+    out = []
+    for line in content.splitlines():
+        line = _GITHUB_PR_RE.sub(' ', line)
+        line = _COMMIT_HASH_RE.sub('', line)
+        line = line.replace('\t', '').rstrip()
+        stripped = line.lstrip()
+        indent = line[:len(line) - len(stripped)]
+        if len(line) > 80:
+            if stripped.startswith('- '):
+                indent += '  '
+            line = textwrap.fill(line, width=80, subsequent_indent=indent)
+        out.append(line)
+    text = '\n'.join(out)
+    # Entries removed above can leave 3+ blank newlines where a blank-line
+    # separator butted up against a removed entry's own blank line;
+    # collapse any such run down to a single blank line (2 newlines).
+    text = re.sub(r'\n{3,}', '\n\n', text).strip()
+    return _join_single_line_paragraphs(text)
+
+
 def _extract_changelog(srctree, pn, old_ver, new_ver, old_tag, new_tag, workspace_path, is_git_source):
     """Extract changelog between old and new version using devtool git tags."""
     changelog_content = None
@@ -723,7 +784,7 @@ def _extract_changelog(srctree, pn, old_ver, new_ver, old_tag, new_tag, workspac
         changelog_content = ''.join(filtered)
 
     # Clean up content for readability and commit message use
-    changelog_content = re.sub(r'\n{3,}', '\n\n', changelog_content).strip()
+    changelog_content = _cleanup_changelog(changelog_content)
     if not changelog_content:
         return None
 


^ permalink raw reply related	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2026-09-18 12:02 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-18 12:01 [PATCH 1/2] devtool: upgrade: write changelog metadata as JSON sidecar daniel.turull
2026-09-18 12:01 ` [PATCH 2/2] devtool: upgrade: clean up changelog content for commit messages daniel.turull

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox