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 9/9] oeqa/oelib: test patch command argv handling
Date: Tue, 23 Jun 2026 15:35:21 +0200 [thread overview]
Message-ID: <20260623133521.17053-10-anders.heimer@est.tech> (raw)
In-Reply-To: <20260623133521.17053-1-anders.heimer@est.tech>
Exercise fallback patch metadata with an author, date and committer name
containing spaces so direct argv execution passes those values to Git
without shell quoting.
Also cover the GitApplyTree and PatchTree run=False paths so
manual-resolution command generation continues to return argv lists
without applying the patch. Use patch filenames with spaces to verify
the paths remain single argv elements.
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 | 98 +++++++++++++++++++++
1 file changed, 98 insertions(+)
diff --git a/meta/lib/oeqa/selftest/cases/oelib/patch.py b/meta/lib/oeqa/selftest/cases/oelib/patch.py
index 69e06b5ac1..9dc37cd0f3 100644
--- a/meta/lib/oeqa/selftest/cases/oelib/patch.py
+++ b/meta/lib/oeqa/selftest/cases/oelib/patch.py
@@ -61,6 +61,37 @@ class TestRunCmd(TestCase):
self.assertEqual(ctx.exception.status, 127)
+class TestPatchTree(TestCase):
+ def test_push_run_false_returns_argv(self):
+ with tempfile.TemporaryDirectory(prefix="oe-patchtree-run-false-") as tmpdir:
+ srcdir = os.path.join(tmpdir, "source")
+ os.mkdir(srcdir)
+ with open(os.path.join(srcdir, "file.txt"), "w") as f:
+ f.write("base\n")
+
+ patch = os.path.join(tmpdir, "patch with spaces.patch")
+ with open(patch, "w") as f:
+ f.write(
+ "--- a/file.txt\n"
+ "+++ b/file.txt\n"
+ "@@ -1 +1 @@\n"
+ "-base\n"
+ "+changed\n"
+ )
+
+ tree = oe.patch.PatchTree(srcdir, PatchTestDataStore(tmpdir))
+ tree.Import({"file": patch, "strippath": "1"}, False)
+
+ cmd = tree.Push(False, run=False)
+
+ self.assertEqual(cmd[:5], [
+ "patch", "--no-backup-if-mismatch", "-p", "1", "-i",
+ ])
+ self.assertEqual(cmd[-1], patch)
+ self.assertIsNone(tree.current())
+ with open(os.path.join(srcdir, "file.txt")) as f:
+ self.assertEqual(f.read(), "base\n")
+
class RecordingGitApplyTree(oe.patch.GitApplyTree):
def __init__(self, *args, **kwargs):
self.commitpatch_called = False
@@ -120,6 +151,8 @@ class TestGitApplyTree(TestCase):
patch = os.path.join(tmpdir, basename)
with open(patch, "w") as f:
f.write(
+ "Author: Fallback Author <fallback.author@example.com>\n"
+ "Date: Fri, 01 Jan 2021 12:34:56 +0000\n"
"Subject: [PATCH] plain diff change\n"
"\n"
"--- a/file.txt\n"
@@ -152,6 +185,14 @@ class TestGitApplyTree(TestCase):
with open(patches[0]) as f:
self.assertIn(expected, f.read())
+ def assert_no_note(self, repo):
+ with self.assertRaises(oe.patch.CmdError):
+ oe.patch.runcmd(
+ ["git", "notes", "--ref", oe.patch.GitApplyTree.notes_ref,
+ "show", "HEAD"],
+ repo,
+ )
+
def test_git_am_preserves_original_patch_name(self):
with tempfile.TemporaryDirectory(prefix="oe-gitapply-am-") as tmpdir:
patchname = "0001-distinct-original-name.patch"
@@ -166,6 +207,51 @@ class TestGitApplyTree(TestCase):
self.assertEqual(f.read(), "git am change\n")
self.assert_note_and_extract(repo, patchname, "+git am change")
+ def test_push_run_false_returns_argv(self):
+ with tempfile.TemporaryDirectory(prefix="oe-gitapply-run-false-") 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))
+ tree._need_dirty_check = lambda: False
+ tree.Import({"file": patch, "strippath": "1"}, False)
+
+ cmd = tree.Push(False, run=False)
+
+ self.assertIsInstance(cmd, list)
+ self.assertEqual(cmd[0], "git")
+ self.assertIn("am", cmd)
+ self.assertEqual(cmd[-1], patch)
+ self.assertFalse(tree.commitpatch_called)
+ self.assertIsNone(tree.current())
+ self.assert_no_note(repo)
+ with open(os.path.join(repo, "file.txt")) as f:
+ self.assertEqual(f.read(), "base\n")
+
+ def test_dirty_push_run_false_returns_argv(self):
+ with tempfile.TemporaryDirectory(prefix="oe-gitapply-run-false-") as tmpdir:
+ patchname = "plain-diff original name.patch"
+ patch = self.make_plain_diff_patch(tmpdir, patchname)
+ repo = self.make_repo(tmpdir, "target")
+ with open(os.path.join(repo, "file.txt"), "a") as f:
+ f.write("dirty\n")
+
+ tree = RecordingGitApplyTree(repo, PatchTestDataStore(tmpdir))
+ tree._need_dirty_check = lambda: True
+ tree.Import({"file": patch, "strippath": "1"}, False)
+
+ cmd = tree.Push(False, run=False)
+
+ self.assertEqual(cmd[:5], [
+ "patch", "--no-backup-if-mismatch", "-p", "1", "-i",
+ ])
+ self.assertEqual(cmd[-1], patch)
+ self.assertFalse(tree.commitpatch_called)
+ self.assertIsNone(tree.current())
+ self.assert_no_note(repo)
+ with open(os.path.join(repo, "file.txt")) as f:
+ self.assertEqual(f.read(), "base\ndirty\n")
+
def test_fallback_preserves_original_patch_name(self):
with tempfile.TemporaryDirectory(prefix="oe-gitapply-fallback-") as tmpdir:
patchname = "plain-diff-original-name.patch"
@@ -178,4 +264,16 @@ class TestGitApplyTree(TestCase):
self.assertTrue(tree.commitpatch_called)
with open(os.path.join(repo, "file.txt")) as f:
self.assertEqual(f.read(), "plain diff change\n")
+ metadata = oe.patch.runcmd([
+ "git", "show", "-s",
+ "--format=%an%n%ae%n%cn%n%ce%n%aI",
+ "HEAD",
+ ], repo).splitlines()
+ self.assertEqual(metadata, [
+ "Fallback Author",
+ "fallback.author@example.com",
+ "OE Test",
+ "oe-test@example.com",
+ "2021-01-01T12:34:56+00:00",
+ ])
self.assert_note_and_extract(repo, patchname, "+plain diff change")
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 ` [PATCH 6/9] oeqa/oelib: test GitApplyTree patch names Anders Heimer
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 ` Anders Heimer [this message]
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-10-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