From patchwork Sat Nov 14 03:28:32 2026
Content-Type: text/plain; charset="utf-8"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
X-Patchwork-Submitter: Tim Orling
X-Patchwork-Id: 104030
X-Patchwork-Delegate: ticotimo@gmail.com
Received: from mail-pj1-f49.google.com (mail-pj1-f49.google.com
[209.85.216.49])
by mx.groups.io with SMTP id smtpd.msgproc02-g2.5305.1794626918243633559
for ;
Fri, 13 Nov 2026 19:28:38 -0800
Authentication-Results: mx.groups.io;
dkim=pass header.i=@gmail.com header.s=20260707 header.b=Fsdq2P/p;
spf=pass (domain: gmail.com, ip: 209.85.216.49, mailfrom: ticotimo@gmail.com)
Received: by mail-pj1-f49.google.com with SMTP id
98e67ed59e1d1-3b08cf16decso867203a91.0
for ;
Fri, 13 Nov 2026 19:28:38 -0800 (PST)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
d=gmail.com; s=20260707; t=1794626917; x=1795231717;
darn=lists.yoctoproject.org;
h=content-transfer-encoding:mime-version:message-id:date:subject:cc
:to:from:from:to:cc:subject:date:message-id:reply-to:content-type;
bh=/akgZZNgczcsbXKgEoyzk/t7tsfE02tnv1WIP50DMEc=;
b=Fsdq2P/pBs9lI0W0aFnLA3NEprc3Jin9Drpedeyvdwt+BB4OT0H8xcrbpTaF1ycJ9n
jJ2RfqYr2wvHvD/VMGNcnCx0IHT+8ZvQh9/wg17tdkIO9F7eukcfSIpyrY11wS7OlZkt
HwSxb5aLB/vO8ZfpQpqZQmplW1w7N9AGO+R3VcCiErur61xLa5g7MB9JCIfKQmImZdrg
loet+uPACexyQsODwNWnP51/cDCLD80t2qo/EWNBtop3uZnNX/mflH4YCORlpTnXoi/Q
mkl+nmVBQhVzxpUJs2OvJIpLZy6pmBCsqI3oUeCab2obJNgeQvyErIqSP1jYVhpoT3AU
vm8Q==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
d=1e100.net; s=20260707; t=1794626917; x=1795231717;
h=content-transfer-encoding:mime-version:message-id:date:subject:cc
:to:from:x-gm-gg:x-gm-message-state:from:to:cc:subject:date
:message-id:reply-to:content-type;
bh=/akgZZNgczcsbXKgEoyzk/t7tsfE02tnv1WIP50DMEc=;
b=EJN2+P7RQvF9gFnANxday1h16Zftr/zGiHUqepJTgdNRUjNK+mq0rtFHSkDWI8/b/k
TIRg4fD4cRg/wdEHiuzHgpl5JoozAg7LYOhvqC87NJu/F6iBtKLOWxEcI48B7wa1tOEL
jUtQgA6B4KebtPrMKzo/eRLuIwoB6ZKeQA65iHDNc6kxrcDMDBLR5c/XHYCQUhllUsEv
UyYV+TaTRxUUJptV/D6iZ/4u7VynfoJIYqUXIaNljkOWzx640iD1gEp24WOzO+gkEESV
+wlsyMYL6uiHo8crs3qBl8a7EF6NepG0OwBEOfnBHVRJ3X1OBXqKyqIZZqyy/nJPTH7X
IrTw==
X-Gm-Message-State: APuU4Z8SOTUZB8e8b0JSHfsSOge4ICVix39Jo7oxCHSONU6scwwoDrPo
H9pDtDRXHkrecBL8V0+gjPJeFMNYG0hcTTXwyfK8gmEhxiyuZO/wg8X2I5+jMUWQ
X-Gm-Gg: AYBFou3BFO1RHDrgAc2UX/+Y2DAx5i/UtrkGJUrkZn4ZbL6/s68a1sMtLhka3EzgcWm
Iwy21AlwOec7C7h3fKxMaIvElaxJNjTnaYorrKabPiw/TAHhcut13lcR/m+oIfW7orbG6BfI84u
clfPwW9j8wH27qiDdmA46QxQKGRLCnYRCHm/5ZO+jraRVEq2agBH2dQImlUc6eipgb9Wj2nAapU
I1nAtoCQHG/soFfjmrHxcpcA2vT3SEHQ3cgqxLlL2OjvjF0mEAYdFyHAurxwfyYsfTdtS4QEuRL
BXOv/wd6yg0Wv/UqA8G+kOiUFCHCU6905S9rwyHk8pNH+Ppnf4cZLStd3cAUP9rs/Nl99UaVh+T
5EtZPd2ZXtCcO6uHdIlOCHIPEAwbnvIhL0zNLp9aET7mhnRcwpuwE9AQN+vzi5/zNhJXhFD3DhH
It04ILwlho8wELhJ5hVRGCOsntP0uTiaSjfPdEbjQbBij0HxleCnH/6OJE3lc8U8mic4V3Mlyf4
Wl4jBqRP1n89dQELjLQMpPM1mZoc4uQ9JDopZGxOHgwgfbAtaE0So+fMa4tGcsu7jIaSJ40KQrK
Rx6BpHjwZB41y5/sWnAaSun+uhFJ6W4k+uyUhpXZkqb7rclZSfDJ7H0Pjl47SA==
X-Received: by 2002:a17:90a:e016:b0:3b1:b9ed:5dd0 with SMTP id
98e67ed59e1d1-3b1b9ed5e3fmr2237460a91.35.1794626917445;
Fri, 13 Nov 2026 19:28:37 -0800 (PST)
Return-Path:
Received: from localhost.localdomain ([69.9.132.159])
by smtp.gmail.com with ESMTPSA id
98e67ed59e1d1-3b1aec3af2dsm6995078a91.9.2026.11.13.19.28.36
(version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256);
Fri, 13 Nov 2026 19:28:36 -0800 (PST)
From: Tim Orling
X-Google-Original-From: Tim Orling
To: yocto-patches@lists.yoctoproject.org
Cc: Tim Orling
Subject: [layerindex-web][PATCH v2] layerindex: show when a layer branch is no
longer updated
Date: Fri, 13 Nov 2026 19:28:32 -0800
Message-ID: <20261114032832.73642-1-tim.orling@konsulko.com>
X-Mailer: git-send-email 2.56.0
MIME-Version: 1.0
List-Id:
X-Webhook-Received: from 45-33-107-173.ip.linodeusercontent.com
[45.33.107.173] by lin-tor-korg-lkml-alma10-1 with HTTPS for
; Sat, 14 Nov 2026 03:28:45 -0000
X-Groupsio-URL: https://lists.yoctoproject.org/g/yocto-patches/message/5362
Updates can be turned off for a layer, a branch or a layer branch, but
only the admin interface showed it, so the layer list and layer pages
gave no hint that the information may be out of date. Show a "not
updated" label with the reason next to the layer in the layer list and
on the layer page.
[YOCTO #14781]
AI-Generated: Claude Opus 5.5
Signed-off-by: Tim Orling
---
v2: use a lighter grey for the "not updated" label (light grey with dark
grey text instead of Bootstrap's label-default), which was too bold with
171 of them in the master layer list. The label keeps label-default, so
a browser with an older copy of additional.css still shows it.
layerindex/models.py | 11 +++++++
layerindex/static/css/additional.css | 8 +++++
layerindex/views.py | 2 +-
templates/layerindex/detail.html | 7 +++++
templates/layerindex/layers.html | 1 +
tests/test_updates_disabled.py | 45 ++++++++++++++++++++++++++++
6 files changed, 73 insertions(+), 1 deletion(-)
create mode 100644 tests/test_updates_disabled.py
base-commit: 08e58cdece30019a6f9e5d14af16ebe20afa6177
diff --git a/layerindex/models.py b/layerindex/models.py
index 1d72c55..d071788 100644
--- a/layerindex/models.py
+++ b/layerindex/models.py
@@ -334,6 +334,17 @@ class LayerBranch(models.Model):
def test_file_url(self):
return self.file_url('conf/layer.conf')
+ def updates_disabled_reason(self):
+ """Why the update script no longer updates this layer branch, if it
+ doesn't"""
+ if self.layer.status == 'X':
+ return 'Updates are disabled for this layer'
+ if not self.branch.updates_enabled:
+ return 'Updates are disabled for the %s branch' % self.branch.name
+ if not self.updates_enabled:
+ return 'Updates are disabled for this layer on the %s branch' % self.branch.name
+ return ''
+
def get_checkout_branch(self):
"""Get the branch that we actually need to check out in the repo"""
if self.actual_branch:
diff --git a/layerindex/static/css/additional.css b/layerindex/static/css/additional.css
index a3c0a3a..dcab5cd 100644
--- a/layerindex/static/css/additional.css
+++ b/layerindex/static/css/additional.css
@@ -321,3 +321,11 @@ td.info {
height: 400px;
overflow-y: scroll;
}
+
+/* "not updated" label: lighter than label-default, still readable. It also
+ has label-default, so a browser with an older copy of this file still
+ shows it. */
+.label-default.label-not-updated {
+ background-color: #e8e8e8;
+ color: #555;
+}
diff --git a/layerindex/views.py b/layerindex/views.py
index 592311f..85c82d6 100644
--- a/layerindex/views.py
+++ b/layerindex/views.py
@@ -443,7 +443,7 @@ class LayerListView(ListView):
def get_queryset(self):
_check_url_branch(self.kwargs)
- return LayerBranch.objects.filter(branch__name=self.kwargs['branch']).filter(layer__status__in=['P', 'X']).order_by('layer__layer_type', '-layer__index_preference', 'layer__name')
+ return LayerBranch.objects.filter(branch__name=self.kwargs['branch']).filter(layer__status__in=['P', 'X']).select_related('branch').order_by('layer__layer_type', '-layer__index_preference', 'layer__name')
def get_context_data(self, **kwargs):
context = super(LayerListView, self).get_context_data(**kwargs)
diff --git a/templates/layerindex/detail.html b/templates/layerindex/detail.html
index 6c20f47..b14d030 100644
--- a/templates/layerindex/detail.html
+++ b/templates/layerindex/detail.html
@@ -125,6 +125,13 @@
Last commit: {{ layerbranch.vcs_last_commit|timesince }} ago ({{ layerbranch.get_checkout_branch }} branch)
{% endif %}
+ {% with reason=layerbranch.updates_disabled_reason %}
+ {% if reason %}
+
+ not updated {{ reason }}, so the information here may be out of date.
+
+ {% endif %}
+ {% endwith %}
{% if layerbranch.active_maintainers.count > 0 %}
{% if layerbranch.active_maintainers|length == 1 %}Maintainer{% else %}Maintainers{% endif %}
diff --git a/templates/layerindex/layers.html b/templates/layerindex/layers.html
index daae8cb..fb07d90 100644
--- a/templates/layerindex/layers.html
+++ b/templates/layerindex/layers.html
@@ -75,6 +75,7 @@
{% for layerbranch in layerbranch_list %}
{{ layerbranch.layer.name }}
+ {% with reason=layerbranch.updates_disabled_reason %}{% if reason %}not updated{% endif %}{% endwith %}
{% if layerbranch.yp_compatible_version %}
{% endif %}
diff --git a/tests/test_updates_disabled.py b/tests/test_updates_disabled.py
new file mode 100644
index 0000000..7fcdf50
--- /dev/null
+++ b/tests/test_updates_disabled.py
@@ -0,0 +1,45 @@
+# layerindex-web - test the indication that a layer branch is no longer updated
+#
+# Licensed under the MIT license, see COPYING.MIT for details
+#
+# SPDX-License-Identifier: MIT
+
+import pytest
+from django.urls import reverse
+
+from layerindex.models import Branch, LayerBranch, LayerItem
+
+
+def make(name, status='P'):
+ master, _ = Branch.objects.get_or_create(name='master', defaults={'bitbake_branch': 'master'})
+ layer = LayerItem.objects.create(name=name, status=status, layer_type='A', summary=name,
+ description=name, vcs_url='git://example.com/%s.git' % name)
+ return LayerBranch.objects.create(layer=layer, branch=master)
+
+
+@pytest.mark.django_db
+def test_updates_disabled_reason():
+ # [YOCTO #14781] updates can be off for the layer, the branch or the layer branch
+ lb = make('meta-a')
+ assert lb.updates_disabled_reason() == ''
+ lb.updates_enabled = False
+ assert lb.updates_disabled_reason() == 'Updates are disabled for this layer on the master branch'
+ lb.branch.updates_enabled = False
+ assert lb.updates_disabled_reason() == 'Updates are disabled for the master branch'
+ lb.layer.status = 'X'
+ assert lb.updates_disabled_reason() == 'Updates are disabled for this layer'
+
+
+@pytest.mark.django_db
+def test_not_updated_label_on_layer_pages(client):
+ make('meta-updated')
+ make('meta-stale', status='X')
+ layers = client.get(reverse('layer_list', args=('master',))).content.decode()
+ assert layers.count('>not updated') == 1
+ assert 'title="Updates are disabled for this layer"' in layers
+
+ page = client.get(reverse('layer_item', args=('master', 'meta-stale'))).content.decode()
+ assert 'not updated' in page
+ assert 'Updates are disabled for this layer, so the information here may be out of date.' in page
+ page = client.get(reverse('layer_item', args=('master', 'meta-updated'))).content.decode()
+ assert 'not updated' not in page
|