* [wrynose][PATCH] oeqa/selftest/devtool: handle existing patch directories in recipe tests
@ 2026-10-19 12:58 Ayoub Zaki
2026-10-20 9:33 ` Yoann Congal
0 siblings, 1 reply; 2+ messages in thread
From: Ayoub Zaki @ 2026-10-19 12:58 UTC (permalink / raw)
To: openembedded-core; +Cc: yoann.congal, Ayoub Zaki
Recipe update and finish tests assume generated patches live in a
directory named after the recipe. Existing files/ or versioned directories
can instead cause staging failures and leave generated files for later
tests. Cleanup can also delete tracked patches that should be preserved.
Share recipe-directory cleanup that resets the index, removes untracked
files and restores tracked files. Stage recipe changes and check generated
patch filenames without assuming a subdirectory, including the
--initial-rev cases. Keep paths that describe known fixture contents.
Validated with devtool.DevtoolUpdateTests.test_devtool_update_recipe and
isolated staging and cleanup checks on both target branches.
AI-Generated: Uses OpenAI Codex
Signed-off-by: Ayoub Zaki <ayoub.zaki@embetrix.com>
---
meta/lib/oeqa/selftest/cases/devtool.py | 65 +++++++++++++------------
1 file changed, 35 insertions(+), 30 deletions(-)
diff --git a/meta/lib/oeqa/selftest/cases/devtool.py b/meta/lib/oeqa/selftest/cases/devtool.py
index b485d752e7..a6fd050a34 100644
--- a/meta/lib/oeqa/selftest/cases/devtool.py
+++ b/meta/lib/oeqa/selftest/cases/devtool.py
@@ -139,6 +139,13 @@ class DevtoolTestCase(OESelftestTestCase):
if expected_status:
self.fail('Missing file changes: %s' % expected_status)
+ def _add_recipe_cleanup(self, recipefile):
+ """Restore a recipe directory in the test checkout, including its index."""
+ cleanup_cmd = ('cd %s && git reset HEAD -- . && git clean -fd -- . '
+ '&& git checkout -- .' % shlex.quote(os.path.dirname(recipefile)))
+ self.add_command_to_tearDown(cleanup_cmd)
+ return cleanup_cmd
+
def _test_recipe_contents(self, recipefile, checkvars, checkinherits):
with open(recipefile, 'r') as f:
invar = None
@@ -1209,11 +1216,10 @@ class DevtoolUpdateTests(DevtoolBase):
result = runCmd('echo "A new file" > devtool-new-file', cwd=tempdir)
result = runCmd('git add devtool-new-file', cwd=tempdir)
result = runCmd('git commit -m "Add a new file"', cwd=tempdir)
- cleanup_cmd = 'cd %s; rm %s/*.patch; git add %s; git checkout %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile))
- self.add_command_to_tearDown(cleanup_cmd)
+ cleanup_cmd = self._add_recipe_cleanup(recipefile)
result = runCmd('devtool update-recipe %s' % testrecipe)
- result = runCmd('git add minicom', cwd=os.path.dirname(recipefile))
- expected_status = [(' M', '.*/%s$' % os.path.basename(recipefile)),
+ result = runCmd('git add .', cwd=os.path.dirname(recipefile))
+ expected_status = [('M ', '.*/%s$' % os.path.basename(recipefile)),
('A ', '.*/0001-Change-the-README.patch$'),
('A ', '.*/0002-Add-a-new-file.patch$')]
self._check_repo_status(os.path.dirname(recipefile), expected_status)
@@ -1225,8 +1231,8 @@ class DevtoolUpdateTests(DevtoolBase):
result = runCmd('git rev-parse devtool-base', cwd=tempdir)
initial_rev = result.output.strip()
result = runCmd('devtool update-recipe --initial-rev %s %s' % (initial_rev, testrecipe))
- result = runCmd('git add minicom', cwd=os.path.dirname(recipefile))
- expected_status = [(' M', '.*/%s$' % os.path.basename(recipefile)),
+ result = runCmd('git add .', cwd=os.path.dirname(recipefile))
+ expected_status = [('M ', '.*/%s$' % os.path.basename(recipefile)),
('A ', '.*/0001-Change-the-README.patch$'),
('A ', '.*/0002-Add-a-new-file.patch$')]
self._check_repo_status(os.path.dirname(recipefile), expected_status)
@@ -1235,8 +1241,8 @@ class DevtoolUpdateTests(DevtoolBase):
result = runCmd('git rev-parse HEAD~1', cwd=tempdir)
midpoint_rev = result.output.strip()
result = runCmd('devtool update-recipe --initial-rev %s %s' % (midpoint_rev, testrecipe))
- result = runCmd('git add minicom', cwd=os.path.dirname(recipefile))
- expected_status = [(' M', '.*/%s$' % os.path.basename(recipefile)),
+ result = runCmd('git add .', cwd=os.path.dirname(recipefile))
+ expected_status = [('M ', '.*/%s$' % os.path.basename(recipefile)),
('A ', '.*/0001-Add-a-new-file.patch$')]
self._check_repo_status(os.path.dirname(recipefile), expected_status)
result = runCmd(cleanup_cmd)
@@ -1271,7 +1277,7 @@ class DevtoolUpdateTests(DevtoolBase):
result = runCmd('echo "A new file" > devtool-new-file', cwd=tempdir)
result = runCmd('git add devtool-new-file', cwd=tempdir)
result = runCmd('git commit -m "Add a new file"', cwd=tempdir)
- self.add_command_to_tearDown('cd %s; rm -rf %s; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile)))
+ cleanup_cmd = self._add_recipe_cleanup(recipefile)
result = runCmd('devtool update-recipe -m srcrev %s' % testrecipe)
expected_status = [(' M', '.*/%s$' % os.path.basename(recipefile))] + \
[(' D', '.*/%s$' % patch) for patch in patches]
@@ -1285,14 +1291,12 @@ class DevtoolUpdateTests(DevtoolBase):
removelines = ['SRCREV = ".*"'] + srcurilines
self._check_diff(result.output, addlines, removelines)
# Now try with auto mode
- runCmd('cd %s; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, os.path.basename(recipefile)))
+ runCmd(cleanup_cmd)
result = runCmd('devtool update-recipe %s' % testrecipe)
- result = runCmd('git rev-parse --show-toplevel', cwd=os.path.dirname(recipefile))
- topleveldir = result.output.strip()
- relpatchpath = os.path.join(os.path.relpath(os.path.dirname(recipefile), topleveldir), testrecipe)
- expected_status = [(' M', os.path.relpath(recipefile, topleveldir)),
- ('??', '%s/0001-Change-the-Makefile.patch' % relpatchpath),
- ('??', '%s/0002-Add-a-new-file.patch' % relpatchpath)]
+ result = runCmd('git add .', cwd=os.path.dirname(recipefile))
+ expected_status = [('M ', '.*/%s$' % os.path.basename(recipefile)),
+ ('A ', '.*/0001-Change-the-Makefile.patch$'),
+ ('A ', '.*/0002-Add-a-new-file.patch$')]
self._check_repo_status(os.path.dirname(recipefile), expected_status)
def test_devtool_update_recipe_append(self):
@@ -1317,7 +1321,7 @@ class DevtoolUpdateTests(DevtoolBase):
# Add a commit
result = runCmd('echo "Additional line" >> README', cwd=tempsrcdir)
result = runCmd('git commit -a -m "Add our custom version"', cwd=tempsrcdir)
- self.add_command_to_tearDown('cd %s; rm -f %s/*.patch; git checkout .' % (os.path.dirname(recipefile), testrecipe))
+ self._add_recipe_cleanup(recipefile)
# Create a temporary layer and add it to bblayers.conf
self._create_temp_layer(templayerdir, True, 'selftestupdaterecipe')
# Create the bbappend
@@ -1391,7 +1395,7 @@ class DevtoolUpdateTests(DevtoolBase):
# Add a commit
result = runCmd('echo "# Additional line" >> Makefile.am', cwd=tempsrcdir)
result = runCmd('git commit -a -m "Change the Makefile"', cwd=tempsrcdir)
- self.add_command_to_tearDown('cd %s; rm -f %s/*.patch; git checkout .' % (os.path.dirname(recipefile), testrecipe))
+ self._add_recipe_cleanup(recipefile)
# Create a temporary layer
os.makedirs(os.path.join(templayerdir, 'conf'))
with open(os.path.join(templayerdir, 'conf', 'layer.conf'), 'w') as f:
@@ -1557,7 +1561,7 @@ class DevtoolUpdateTests(DevtoolBase):
self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
# (don't bother with cleaning the recipe on teardown, we won't be building it)
result = runCmd('devtool modify %s' % testrecipe)
- self.add_command_to_tearDown('cd %s; rm %s/*; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile)))
+ self._add_recipe_cleanup(recipefile)
result = runCmd('devtool finish --force-patch-refresh %s meta-selftest' % testrecipe)
# Check recipe got changed as expected
with open(newpatchfile, 'r') as f:
@@ -1584,7 +1588,7 @@ class DevtoolUpdateTests(DevtoolBase):
self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
# (don't bother with cleaning the recipe on teardown, we won't be building it)
result = runCmd('devtool modify %s' % testrecipe)
- self.add_command_to_tearDown('cd %s; rm %s/*; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile)))
+ self._add_recipe_cleanup(recipefile)
result = runCmd('devtool finish --force-patch-refresh %s meta-selftest' % testrecipe)
# Check recipe got changed as expected
with open(newpatchfile, 'r') as f:
@@ -1611,7 +1615,7 @@ class DevtoolUpdateTests(DevtoolBase):
result = runCmd('devtool modify %s' % testrecipe)
# Modify one file
runCmd('echo "Another line" >> file2', cwd=os.path.join(self.workspacedir, 'sources', testrecipe))
- self.add_command_to_tearDown('cd %s; rm %s/*; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile)))
+ self._add_recipe_cleanup(recipefile)
result = runCmd('devtool update-recipe %s' % testrecipe)
expected_status = [(' M', '.*/%s/file2$' % testrecipe)]
self._check_repo_status(os.path.dirname(recipefile), expected_status)
@@ -1634,7 +1638,7 @@ class DevtoolUpdateTests(DevtoolBase):
srctree = os.path.join(self.workspacedir, 'sources', testrecipe)
runCmd('echo "Another line" >> README', cwd=srctree)
runCmd('git commit -a --amend --no-edit --no-verify', cwd=srctree)
- self.add_command_to_tearDown('cd %s; rm %s/*; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile)))
+ self._add_recipe_cleanup(recipefile)
result = runCmd('devtool update-recipe %s' % testrecipe)
expected_status = [(' M', '.*/%s/readme.patch.gz$' % testrecipe)]
self._check_repo_status(os.path.dirname(recipefile), expected_status)
@@ -1664,7 +1668,7 @@ class DevtoolUpdateTests(DevtoolBase):
contents = f.read().rstrip()
self.assertEqual(contents, 'Modified version', 'File has apparently not been overwritten as it should have been')
# Test devtool update-recipe without modifying any files
- self.add_command_to_tearDown('cd %s; rm %s/*; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile)))
+ self._add_recipe_cleanup(recipefile)
result = runCmd('devtool update-recipe %s' % testrecipe)
expected_status = []
self._check_repo_status(os.path.dirname(recipefile), expected_status)
@@ -1700,12 +1704,13 @@ class DevtoolUpdateTests(DevtoolBase):
# Now try updating original recipe
recipefile = bb_vars['FILE']
recipedir = os.path.dirname(recipefile)
- self.add_command_to_tearDown('cd %s; rm -f %s/*.patch; git checkout .' % (recipedir, testrecipe))
+ cleanup_cmd = self._add_recipe_cleanup(recipefile)
result = runCmd('devtool update-recipe %s' % testrecipe)
- expected_status = [(' M', '.*/%s$' % os.path.basename(recipefile)),
- ('??', '.*/%s/%s/$' % (testrecipe, testrecipe))]
- self._check_repo_status(os.path.dirname(recipefile), expected_status)
- result = runCmd('git diff %s' % os.path.basename(recipefile), cwd=os.path.dirname(recipefile))
+ result = runCmd('git add .', cwd=recipedir)
+ expected_status = [('M ', '.*/%s$' % os.path.basename(recipefile)),
+ ('A ', '.*/0001-Add-a-comment.patch$')]
+ self._check_repo_status(recipedir, expected_status)
+ result = runCmd('git diff --cached %s' % os.path.basename(recipefile), cwd=recipedir)
removelines = ['SRC_URI = "git://.*"']
addlines = [
'SRC_URI = "git://.* \\\\',
@@ -1714,7 +1719,7 @@ class DevtoolUpdateTests(DevtoolBase):
]
self._check_diff(result.output, addlines, removelines)
# Put things back so we can run devtool finish on a different layer
- runCmd('cd %s; rm -f %s/*.patch; git checkout .' % (recipedir, testrecipe))
+ runCmd(cleanup_cmd)
# Run devtool finish
res = re.search('recipes-.*', recipedir)
self.assertTrue(res, 'Unable to find recipe subdirectory')
@@ -2437,7 +2442,7 @@ class DevtoolUpgradeTests(DevtoolBase):
self.track_for_cleanup(tempdir)
self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
result = runCmd('devtool modify %s %s' % (recipe, tempdir))
- self.add_command_to_tearDown('cd %s; rm %s/*; git checkout %s %s' % (recipedir, recipe, recipe, os.path.basename(recipefile)))
+ self._add_recipe_cleanup(recipefile)
self.assertExists(os.path.join(tempdir, 'CMakeLists.txt'), 'Extracted source could not be found')
# Make a change to one of the existing commits
result = runCmd('echo "# A comment " >> CMakeLists.txt', cwd=tempdir)
--
2.53.0
^ permalink raw reply related [flat|nested] 2+ messages in thread
* Re: [wrynose][PATCH] oeqa/selftest/devtool: handle existing patch directories in recipe tests
2026-10-19 12:58 [wrynose][PATCH] oeqa/selftest/devtool: handle existing patch directories in recipe tests Ayoub Zaki
@ 2026-10-20 9:33 ` Yoann Congal
0 siblings, 0 replies; 2+ messages in thread
From: Yoann Congal @ 2026-10-20 9:33 UTC (permalink / raw)
To: Ayoub Zaki, openembedded-core
On Mon Oct 19, 2026 at 2:58 PM CEST, Ayoub Zaki wrote:
> Recipe update and finish tests assume generated patches live in a
> directory named after the recipe. Existing files/ or versioned directories
> can instead cause staging failures and leave generated files for later
> tests. Cleanup can also delete tracked patches that should be preserved.
>
> Share recipe-directory cleanup that resets the index, removes untracked
> files and restores tracked files. Stage recipe changes and check generated
> patch filenames without assuming a subdirectory, including the
> --initial-rev cases. Keep paths that describe known fixture contents.
>
> Validated with devtool.DevtoolUpdateTests.test_devtool_update_recipe and
> isolated staging and cleanup checks on both target branches.
>
> AI-Generated: Uses OpenAI Codex
> Signed-off-by: Ayoub Zaki <ayoub.zaki@embetrix.com>
> ---
> meta/lib/oeqa/selftest/cases/devtool.py | 65 +++++++++++++------------
> 1 file changed, 35 insertions(+), 30 deletions(-)
Hello,
This needs to be sent to master first. Then, blacksail.
Regards,
--
Yoann Congal
Smile ECS
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2026-10-20 9:33 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-19 12:58 [wrynose][PATCH] oeqa/selftest/devtool: handle existing patch directories in recipe tests Ayoub Zaki
2026-10-20 9:33 ` Yoann Congal
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox