diff mbox series

[layerindex-web] update: disable updates for a layer branch whose layer has gone

Message ID 20261114052504.96229-1-tim.orling@konsulko.com
State Under Review
Delegated to: Tim Orling
Headers show
Series [layerindex-web] update: disable updates for a layer branch whose layer has gone | expand

Commit Message

Tim Orling Nov. 14, 2026, 5:25 a.m. UTC
When a layer was removed from a branch (its subdirectory or its
conf/layer.conf gone), every update kept trying it and recording the
same error, until an admin deleted the layer branch. Disable updates
for the layer branch instead, and say so in the error. Unlike deleting
it, this keeps the layer branch's data and can be undone; the layer
pages show it as not updated.

[YOCTO #12922]

AI-Generated: Claude Opus 5.5
Signed-off-by: Tim Orling <tim.orling@konsulko.com>
---
This applies on top of "[PATCH 0/3] Report problems with the first
parse of a layer" (bugs 12130, 13490, 13489), which records these
errors against the layer, and on master-next. It disables updates
rather than deleting the layer branch, as discussed in the bug.

On a test instance loaded with a copy of the layers.openembedded.org
database, none of the last three updates hit these errors, so it would
not disable any layer branch today.

 layerindex/update.py | 21 +++++++++++++++++----
 tests/test_update.py | 11 ++++++++---
 2 files changed, 25 insertions(+), 7 deletions(-)


base-commit: 08e58cdece30019a6f9e5d14af16ebe20afa6177
prerequisite-patch-id: 85be5c2fe68b937570c6e8be5a911e92864cdf63
prerequisite-patch-id: 85ea51619f1ba4ca8253c1df2d0f7689823f1d22
prerequisite-patch-id: e0e8ba9340973102abc551c2c349edbf518d6d48
diff mbox series

Patch

diff --git a/layerindex/update.py b/layerindex/update.py
index dd794dd..72bad6c 100755
--- a/layerindex/update.py
+++ b/layerindex/update.py
@@ -128,7 +128,7 @@  def print_subdir_error(newbranch, layername, vcs_subdir, branchdesc):
     if newbranch:
         logger.info("Skipping update of layer %s for branch %s - subdirectory %s does not exist on this branch" % (layername, branchdesc, vcs_subdir))
     elif vcs_subdir:
-        return "Subdirectory for layer %s does not exist on branch %s - if this is legitimate, the layer branch record should be deleted" % (layername, branchdesc)
+        return "Subdirectory %s for layer %s does not exist on branch %s" % (vcs_subdir, layername, branchdesc)
     return None
 
 def extract_value(valuename, output):
@@ -291,6 +291,15 @@  def main():
         if not options.dryrun:
             layerupdate.save()
 
+    def disable_layerbranch_updates(layer, branchobj, layerbranch, msg):
+        """The layer has gone from this branch: record why and stop updating
+        it. Unlike deleting the layer branch, this keeps its data and can be
+        undone by enabling updates again."""
+        if not options.dryrun:
+            layerbranch.updates_enabled = False
+            layerbranch.save(update_fields=['updates_enabled'])
+        record_layer_error(layer, branchobj, '%s - updates for this layer branch have been disabled' % msg)
+
     try:
         lockfn = os.path.join(fetchdir, "layerindex.lock")
         lockfile = utils.lock_file(lockfn, options.timeout, logger)
@@ -442,7 +451,7 @@  def main():
                         if not topcommit:
                             errmsg = print_subdir_error(newbranch, layer.name, layerbranch.vcs_subdir, branchdesc)
                             if errmsg:
-                                record_layer_error(layer, branchobj, errmsg)
+                                disable_layerbranch_updates(layer, branchobj, layerbranch, errmsg)
                             if not (newbranch and layerbranch.vcs_subdir):
                                 record_layer_error(layer, branchobj, "Failed to get last revision for layer %s on branch %s" % (layer.name, branchdesc))
                             continue
@@ -462,11 +471,15 @@  def main():
                         if layerbranch.vcs_subdir and not os.path.exists(layerdir):
                             errmsg = print_subdir_error(newbranch, layer.name, layerbranch.vcs_subdir, branchdesc)
                             if errmsg:
-                                record_layer_error(layer, branchobj, errmsg)
+                                disable_layerbranch_updates(layer, branchobj, layerbranch, errmsg)
                             continue
 
                         if not os.path.exists(os.path.join(layerdir, 'conf/layer.conf')):
-                            record_layer_error(layer, branchobj, "conf/layer.conf not found for layer %s (branch %s) - is subdirectory set correctly?" % (layer.name, branch))
+                            errmsg = "conf/layer.conf not found for layer %s (branch %s) - is subdirectory set correctly?" % (layer.name, branch)
+                            if newbranch:
+                                record_layer_error(layer, branchobj, errmsg)
+                            else:
+                                disable_layerbranch_updates(layer, branchobj, layerbranch, errmsg)
                             continue
 
                     fd, initial_fn = tempfile.mkstemp(prefix='layerindex-initial-')
diff --git a/tests/test_update.py b/tests/test_update.py
index 3266d44..8cd3161 100644
--- a/tests/test_update.py
+++ b/tests/test_update.py
@@ -173,18 +173,19 @@  def test_initial_values_not_in_output(import_layer):
     assert 'BBFILE_COLLECTIONS = ' not in result.stdout
     assert 'Unable to find BBFILE_COLLECTIONS' not in result.stdout
 
-def set_layerbranch(subdir, last_rev):
+def set_layerbranch(subdir, last_rev, updates_enabled=True):
     # In a separate process, so that update.py sees the change: the tests run
     # in a transaction
     run_cmd('python3 manage.py shell -c "from layerindex.models import LayerBranch; '
             'LayerBranch.objects.filter(layer__name=\'meta-layerindex-test\').update('
-            'vcs_subdir=\'%s\', vcs_last_rev=\'%s\')"' % (subdir, last_rev), cwd=basepath)
+            'vcs_subdir=\'%s\', vcs_last_rev=\'%s\', updates_enabled=%s)"' % (subdir, last_rev, updates_enabled), cwd=basepath)
 
 def test_first_parse_error_recorded_against_layer(import_layer, repo, db_access_without_rollback_and_truncate):
     # [YOCTO #13490] an error that stops a layer being parsed is recorded
     # in the layer's update history, not only in the overall update log
     from layerindex.models import LayerBranch, LayerUpdate
     layerbranch = LayerBranch.objects.get(layer__name='meta-layerindex-test')
+    saved = (layerbranch.vcs_subdir, layerbranch.vcs_last_rev)
     set_layerbranch('meta-layerindex-test/recipes-example', '')
     try:
         result = subprocess.run("layerindex/update.py -l meta-layerindex-test --nofetch --nocheckout",
@@ -193,8 +194,12 @@  def test_first_parse_error_recorded_against_layer(import_layer, repo, db_access_
         layerupdate = LayerUpdate.objects.filter(layer=layerbranch.layer).order_by('-id').first()
         assert 'conf/layer.conf not found for layer meta-layerindex-test' in layerupdate.log, result.stdout
         assert layerupdate.errors == 1
+        # [YOCTO #12922] the layer has gone from the branch: stop updating it
+        assert 'updates for this layer branch have been disabled' in layerupdate.log
+        layerbranch.refresh_from_db()
+        assert not layerbranch.updates_enabled
     finally:
-        set_layerbranch(layerbranch.vcs_subdir, layerbranch.vcs_last_rev)
+        set_layerbranch(*saved)