From: Anders Heimer <anders.heimer@est.tech>
To: openembedded-core@lists.openembedded.org
Cc: Anders Heimer <anders.heimer@est.tech>,
Daniel Turull <daniel.turull@ericsson.com>
Subject: [PATCH 6/9] oeqa/oelib: test GitApplyTree patch names
Date: Tue, 23 Jun 2026 15:35:18 +0200 [thread overview]
Message-ID: <20260623133521.17053-7-anders.heimer@est.tech> (raw)
In-Reply-To: <20260623133521.17053-1-anders.heimer@est.tech>
Exercise both the git-am path and the fallback commit path through
GitApplyTree.Import() and Push(). Verify that refs/notes/devtool records
the original patch filename and that extractPatches() recreates patches
with that name.
AI-Generated: Claude Opus 4.6
Reviewed-by: Daniel Turull <daniel.turull@ericsson.com>
Signed-off-by: Anders Heimer <anders.heimer@est.tech>
---
meta/lib/oeqa/selftest/cases/oelib/patch.py | 136 ++++++++++++++++++++
1 file changed, 136 insertions(+)
diff --git a/meta/lib/oeqa/selftest/cases/oelib/patch.py b/meta/lib/oeqa/selftest/cases/oelib/patch.py
index 4cbfef4ce6..69e06b5ac1 100644
--- a/meta/lib/oeqa/selftest/cases/oelib/patch.py
+++ b/meta/lib/oeqa/selftest/cases/oelib/patch.py
@@ -4,12 +4,28 @@
# SPDX-License-Identifier: MIT
#
+import os
+import shutil
+import subprocess
import sys
+import tempfile
from unittest.case import TestCase
import oe.patch
+class PatchTestDataStore:
+ def __init__(self, workdir):
+ self.vars = {
+ "PATCH_GIT_USER_NAME": "OE Test",
+ "PATCH_GIT_USER_EMAIL": "oe-test@example.com",
+ "WORKDIR": workdir,
+ }
+
+ def getVar(self, name):
+ return self.vars.get(name, "")
+
+
class TestRunCmd(TestCase):
def test_runcmd_preserves_argv_elements(self):
output = oe.patch.runcmd([
@@ -43,3 +59,123 @@ class TestRunCmd(TestCase):
])
self.assertEqual(ctx.exception.status, 127)
+
+
+class RecordingGitApplyTree(oe.patch.GitApplyTree):
+ def __init__(self, *args, **kwargs):
+ self.commitpatch_called = False
+ super().__init__(*args, **kwargs)
+
+ def _commitpatch(self, patch, *args):
+ self.commitpatch_called = True
+ return super()._commitpatch(patch, *args)
+
+
+class TestGitApplyTree(TestCase):
+ def setUp(self):
+ if shutil.which("git") is None:
+ self.skipTest("git not found")
+ if shutil.which("patch") is None:
+ self.skipTest("patch not found")
+
+ def git(self, cwd, *args):
+ subprocess.check_call(
+ ["git"] + list(args),
+ cwd=cwd,
+ stdout=subprocess.DEVNULL,
+ stderr=subprocess.DEVNULL,
+ )
+
+ def make_repo(self, tmpdir, name, text="base\n"):
+ repo = os.path.join(tmpdir, name)
+ os.mkdir(repo)
+ self.git(repo, "init")
+ self.git(repo, "config", "user.name", "OE Test")
+ self.git(repo, "config", "user.email", "oe-test@example.com")
+ with open(os.path.join(repo, "file.txt"), "w") as f:
+ f.write(text)
+ self.git(repo, "add", "file.txt")
+ self.git(repo, "commit", "-m", "base")
+ return repo
+
+ def make_git_am_patch(self, tmpdir, basename):
+ repo = self.make_repo(tmpdir, "source")
+ with open(os.path.join(repo, "file.txt"), "w") as f:
+ f.write("git am change\n")
+ self.git(repo, "commit", "-am", "git am change")
+ patchdir = os.path.join(tmpdir, "patches")
+ os.mkdir(patchdir)
+ subprocess.check_call(
+ ["git", "format-patch", "-1", "HEAD", "-o", patchdir],
+ cwd=repo,
+ stdout=subprocess.DEVNULL,
+ stderr=subprocess.DEVNULL,
+ )
+ patch = os.path.join(patchdir, os.listdir(patchdir)[0])
+ renamed = os.path.join(patchdir, basename)
+ os.rename(patch, renamed)
+ return renamed
+
+ def make_plain_diff_patch(self, tmpdir, basename):
+ patch = os.path.join(tmpdir, basename)
+ with open(patch, "w") as f:
+ f.write(
+ "Subject: [PATCH] plain diff change\n"
+ "\n"
+ "--- a/file.txt\n"
+ "+++ b/file.txt\n"
+ "@@ -1 +1 @@\n"
+ "-base\n"
+ "+plain diff change\n"
+ )
+ return patch
+
+ def apply_patch(self, tree, patch):
+ tree._need_dirty_check = lambda: False
+ tree.Import({"file": patch, "strippath": "1"}, False)
+ tree.Push(False)
+
+ def assert_note_and_extract(self, repo, patchname, expected):
+ note = oe.patch.runcmd(
+ ["git", "notes", "--ref", oe.patch.GitApplyTree.notes_ref,
+ "show", "HEAD"],
+ repo,
+ )
+ self.assertIn("%s: %s" % (oe.patch.GitApplyTree.original_patch,
+ patchname), note)
+
+ with tempfile.TemporaryDirectory(prefix="oe-patch-extract-") as outdir:
+ patches = oe.patch.GitApplyTree.extractPatches(
+ repo, {"": "HEAD~1"}, outdir
+ )
+ self.assertEqual([os.path.basename(p) for p in patches], [patchname])
+ with open(patches[0]) as f:
+ self.assertIn(expected, f.read())
+
+ def test_git_am_preserves_original_patch_name(self):
+ with tempfile.TemporaryDirectory(prefix="oe-gitapply-am-") as tmpdir:
+ patchname = "0001-distinct-original-name.patch"
+ patch = self.make_git_am_patch(tmpdir, patchname)
+ repo = self.make_repo(tmpdir, "target")
+ tree = RecordingGitApplyTree(repo, PatchTestDataStore(tmpdir))
+
+ self.apply_patch(tree, patch)
+
+ self.assertFalse(tree.commitpatch_called)
+ with open(os.path.join(repo, "file.txt")) as f:
+ self.assertEqual(f.read(), "git am change\n")
+ self.assert_note_and_extract(repo, patchname, "+git am change")
+
+ def test_fallback_preserves_original_patch_name(self):
+ with tempfile.TemporaryDirectory(prefix="oe-gitapply-fallback-") as tmpdir:
+ patchname = "plain-diff-original-name.patch"
+ patch = self.make_plain_diff_patch(tmpdir, patchname)
+ repo = self.make_repo(tmpdir, "target")
+ tree = RecordingGitApplyTree(repo, PatchTestDataStore(tmpdir))
+
+ self.apply_patch(tree, patch)
+
+ self.assertTrue(tree.commitpatch_called)
+ with open(os.path.join(repo, "file.txt")) as f:
+ self.assertEqual(f.read(), "plain diff change\n")
+ self.assert_note_and_extract(repo, patchname, "+plain diff change")
next prev parent reply other threads:[~2026-06-23 13:35 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-06-23 13:35 [PATCH 0/9] oe/patch: execute patch commands without an implicit shell Anders Heimer
2026-06-23 13:35 ` [PATCH 1/9] oe/patch: drop shell=True from runcmd Anders Heimer
2026-06-23 13:35 ` [PATCH 2/9] oeqa/oelib: add runcmd tests Anders Heimer
2026-06-23 13:35 ` [PATCH 3/9] oe/patch: convert simple runcmd shell callers Anders Heimer
2026-06-23 13:35 ` [PATCH 4/9] oe/patch: avoid shell pipeline in _applypatch Anders Heimer
2026-06-23 13:35 ` [PATCH 5/9] oe/patch: remove obsolete PATCHFILE assignment Anders Heimer
2026-06-23 13:35 ` Anders Heimer [this message]
2026-06-23 13:35 ` [PATCH 7/9] oe/patch: pass GitApplyTree commands as argv lists Anders Heimer
2026-06-23 13:35 ` [PATCH 8/9] oe/patch: return manual-resolution " Anders Heimer
2026-06-23 13:35 ` [PATCH 9/9] oeqa/oelib: test patch command argv handling Anders Heimer
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260623133521.17053-7-anders.heimer@est.tech \
--to=anders.heimer@est.tech \
--cc=daniel.turull@ericsson.com \
--cc=openembedded-core@lists.openembedded.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox