| Message ID | 20251117130451.1711036-1-stondo@gmail.com |
|---|---|
| State | Accepted, archived |
| Commit | 52ab3b640c6bb7ece34cb4ea6026fd6375f17af4 |
| Headers | show |
| Series | [v2] spdx30_tasks: Fix SPDX_CUSTOM_ANNOTATION_VARS implementation | expand |
On Mon Nov 17, 2025 at 2:04 PM CET, Stefano Tondo wrote: > From: Stefano Tondo <stefano.tondo.ext@siemens.com> > > Fix incorrect function call when processing SPDX_CUSTOM_ANNOTATION_VARS. > The code was calling new_annotation() as a standalone function, but it > should be called as a method on the build_objset object. > > Error: > new_annotation(d, build_objset, build, ...) > > Corrected to: > build_objset.new_annotation(d, build_objset, build, ...) > > This bug would cause a NameError at runtime if SPDX_CUSTOM_ANNOTATION_VARS > was set to a non-empty value, preventing SPDX document generation. > > The fix aligns with how new_annotation() is called elsewhere in the > codebase and matches the SBOMObjset class method signature. > > Signed-off-by: Stefano Tondo <stefano.tondo.ext@siemens.com> > > --- > Changes in v2: > - Fixed test bugs: corrected SPDX file path from packages/ to recipes/ > - Fixed test bugs: removed parentheses from objset.objects() call > - Fixed whitespace formatting in test code > --- Hi Stefano, Thanks for the v2, but it looks like the test is still failing with a similar error: 2025-11-18 18:36:56,500 - oe-selftest - INFO - spdx.SPDX30Check.test_custom_annotation_vars (subunit.RemotedTestCase) 2025-11-18 18:36:56,500 - oe-selftest - INFO - ... FAIL ... File "/srv/pokybuild/yocto-worker/oe-selftest-debian/build/layers/openembedded-core/meta/lib/oeqa/selftest/cases/spdx.py", line 330, in test_custom_annotation_vars self.assertIsNotNone(build, "Unable to find Build element") ~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/lib/python3.13/unittest/case.py", line 1309, in assertIsNotNone self.fail(self._formatMessage(msg, standardMsg)) ~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/lib/python3.13/unittest/case.py", line 732, in fail raise self.failureException(msg) AssertionError: unexpectedly None : Unable to find Build element https://autobuilder.yoctoproject.org/valkyrie/#/builders/35/builds/2716 https://autobuilder.yoctoproject.org/valkyrie/#/builders/48/builds/2610 https://autobuilder.yoctoproject.org/valkyrie/#/builders/23/builds/2852 Can you have a look at these? Thanks, Mathieu
Hi Mathieu, Weird, this time oe-selftest was passing. Anything else I need to check locally to make sure it is working properly? 2025-11-19 12:25:28,520 - oe-selftest - INFO - test_custom_annotation_vars (spdx.SPDX30Check.test_custom_annotation_vars) 2025-11-19 12:26:22,548 - oe-selftest - INFO - Found ANNOTATION1: ANNOTATION1=TestAnnotation1 2025-11-19 12:26:22,548 - oe-selftest - INFO - Found ANNOTATION2: ANNOTATION2=TestAnnotation2 2025-11-19 12:26:22,549 - oe-selftest - INFO - ... ok 2025-11-19 12:26:27,823 - oe-selftest - INFO - ---------------------------------------------------------------------- 2025-11-19 12:26:27,823 - oe-selftest - INFO - Ran 1 test in 59.471s 2025-11-19 12:26:27,823 - oe-selftest - INFO - OK 2025-11-19 12:26:32,996 - oe-selftest - INFO - RESULTS: 2025-11-19 12:26:32,996 - oe-selftest - INFO - RESULTS - spdx.SPDX30Check.test_custom_annotation_vars: PASSED (54.03s) 2025-11-19 12:26:32,997 - oe-selftest - INFO - SUMMARY: 2025-11-19 12:26:32,997 - oe-selftest - INFO - oe-selftest () - Ran 1 test in 59.471s 2025-11-19 12:26:32,997 - oe-selftest - INFO - oe-selftest - OK - All required tests passed (successes=1, skipped=0, failures=0, errors=0) Best regards, Stefano
On Wed Nov 19, 2025 at 1:33 PM CET, Stefano Tondo wrote: > Hi Mathieu, > > Weird, this time oe-selftest was passing. Anything else I need to check locally to make sure it is working properly? > > 2025-11-19 12:25:28,520 - oe-selftest - INFO - test_custom_annotation_vars (spdx.SPDX30Check.test_custom_annotation_vars) > 2025-11-19 12:26:22,548 - oe-selftest - INFO - Found ANNOTATION1: ANNOTATION1=TestAnnotation1 > 2025-11-19 12:26:22,548 - oe-selftest - INFO - Found ANNOTATION2: ANNOTATION2=TestAnnotation2 > 2025-11-19 12:26:22,549 - oe-selftest - INFO - ... ok > 2025-11-19 12:26:27,823 - oe-selftest - INFO - ---------------------------------------------------------------------- > 2025-11-19 12:26:27,823 - oe-selftest - INFO - Ran 1 test in 59.471s > 2025-11-19 12:26:27,823 - oe-selftest - INFO - OK > 2025-11-19 12:26:32,996 - oe-selftest - INFO - RESULTS: > 2025-11-19 12:26:32,996 - oe-selftest - INFO - RESULTS - spdx.SPDX30Check.test_custom_annotation_vars: PASSED (54.03s) > 2025-11-19 12:26:32,997 - oe-selftest - INFO - SUMMARY: > 2025-11-19 12:26:32,997 - oe-selftest - INFO - oe-selftest () - Ran 1 test in 59.471s > 2025-11-19 12:26:32,997 - oe-selftest - INFO - oe-selftest - OK - All required tests passed (successes=1, skipped=0, failures=0, errors=0) > > Best regards, > Stefano > Hi Stefano, I was able to reproduce this locally, using: - oecore: https://git.yoctoproject.org/poky-ci-archive/tag/?h=oecore/autobuilder.yoctoproject.org/valkyrie/a-full-2740 - bitbake: https://git.yoctoproject.org/poky-ci-archive/tag/?h=bitbake/autobuilder.yoctoproject.org/valkyrie/a-full-2740 in local.conf: MACHINE = "qemux86-64" SANITY_TESTED_DISTROS = "" An then: oe-selftest -r spdx.SPDX30Check.test_custom_annotation_vars Thanks, Mathieu
diff --git a/meta/lib/oe/spdx30_tasks.py b/meta/lib/oe/spdx30_tasks.py index f2f133005d..4d11b3c289 100644 --- a/meta/lib/oe/spdx30_tasks.py +++ b/meta/lib/oe/spdx30_tasks.py @@ -498,9 +498,7 @@ def create_spdx(d): build_objset.set_is_native(is_native) for var in (d.getVar("SPDX_CUSTOM_ANNOTATION_VARS") or "").split(): - new_annotation( - d, - build_objset, + build_objset.new_annotation( build, "%s=%s" % (var, d.getVar(var)), oe.spdx30.AnnotationType.other, diff --git a/meta/lib/oeqa/selftest/cases/spdx.py b/meta/lib/oeqa/selftest/cases/spdx.py index 8cd4e83ca2..eda41cf952 100644 --- a/meta/lib/oeqa/selftest/cases/spdx.py +++ b/meta/lib/oeqa/selftest/cases/spdx.py @@ -286,3 +286,77 @@ class SPDX30Check(SPDX3CheckBase, OESelftestTestCase): break else: self.assertTrue(False, "Unable to find imported Host SpdxID") + + def test_custom_annotation_vars(self): + """ + Test that SPDX_CUSTOM_ANNOTATION_VARS properly creates annotations + without runtime errors. This is a regression test for the bug where + new_annotation() was called as a standalone function instead of as + a method on build_objset, causing a NameError. + + The test verifies: + 1. The build completes successfully (no NameError) + 2. Each configured annotation variable appears exactly once + 3. The annotation values match the configured variables + + We check for exact equality (not >=) to prevent regressions where + one annotation might appear multiple times while another is missing. + """ + ANNOTATION_VAR1 = "TestAnnotation1" + ANNOTATION_VAR2 = "TestAnnotation2" + + # This will fail with NameError if new_annotation() is called incorrectly + objset = self.check_recipe_spdx( + "base-files", + "{DEPLOY_DIR_SPDX}/{MACHINE_ARCH}/packages/package-base-files.spdx.json", + extraconf=textwrap.dedent( + f"""\ + ANNOTATION1 = "{ANNOTATION_VAR1}" + ANNOTATION2 = "{ANNOTATION_VAR2}" + SPDX_CUSTOM_ANNOTATION_VARS = "ANNOTATION1 ANNOTATION2" + """ + ), + ) + + # If we got here, the build succeeded (no NameError) + # Now verify the annotations were actually created + + # Find the build element + build = None + for o in objset.foreach_type(oe.spdx30.build_Build): + build = o + break + + self.assertIsNotNone(build, "Unable to find Build element") + + # Find annotation objects that reference our build + found_annotations = [] + for obj in objset.objects(): + if isinstance(obj, oe.spdx30.Annotation): + if hasattr(obj, "subject") and build._id == obj.subject._id: + found_annotations.append(obj) + + # Check each annotation separately to ensure exactly one occurrence of each + annotation1_count = 0 + annotation2_count = 0 + + for annotation in found_annotations: + if hasattr(annotation, "statement"): + if f"ANNOTATION1={ANNOTATION_VAR1}" in annotation.statement: + annotation1_count += 1 + self.logger.info(f"Found ANNOTATION1: {annotation.statement}") + if f"ANNOTATION2={ANNOTATION_VAR2}" in annotation.statement: + annotation2_count += 1 + self.logger.info(f"Found ANNOTATION2: {annotation.statement}") + + # Each annotation should appear exactly once + self.assertEqual( + annotation1_count, + 1, + f"Expected exactly 1 occurrence of ANNOTATION1, found {annotation1_count}", + ) + self.assertEqual( + annotation2_count, + 1, + f"Expected exactly 1 occurrence of ANNOTATION2, found {annotation2_count}", + )