Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package openSUSE-release-tools for 
openSUSE:Factory checked in at 2026-09-18 22:07:36
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/openSUSE-release-tools (Old)
 and      /work/SRC/openSUSE:Factory/.openSUSE-release-tools.new.383539 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "openSUSE-release-tools"

Fri Sep 18 22:07:36 2026 rev:559 rq:1378763 version:20260911.6454091f

Changes:
--------
--- 
/work/SRC/openSUSE:Factory/openSUSE-release-tools/openSUSE-release-tools.changes
    2026-08-31 15:59:13.614268730 +0200
+++ 
/work/SRC/openSUSE:Factory/.openSUSE-release-tools.new.383539/openSUSE-release-tools.changes
        2026-09-18 22:08:31.766599758 +0200
@@ -1,0 +2,43 @@
+Fri Sep 11 07:41:39 UTC 2026 - [email protected]
+
+- Update to version 20260911.6454091f:
+  * staging_accept: update Factory version in devel:ARM:Factory:ARMv9 on accept
+  * staging_accept: update Factory version in LegacyARM port on accept
+
+-------------------------------------------------------------------
+Thu Sep 10 14:29:29 UTC 2026 - [email protected]
+
+- Update to version 20260910.2da304ae:
+  * dashboard: Add LegacyARM and ARMv9
+
+-------------------------------------------------------------------
+Thu Sep 10 09:11:24 UTC 2026 - [email protected]
+
+- Update to version 20260910.71fb706c:
+  * gocd: Add configuration for openSUSE:Factory:LegacyARM
+
+-------------------------------------------------------------------
+Fri Sep 04 12:08:10 UTC 2026 - [email protected]
+
+- Update to version 20260904.0a94d671:
+  * container_cleaner.py: Always log packages being deleted
+
+-------------------------------------------------------------------
+Fri Sep 04 09:39:46 UTC 2026 - [email protected]
+
+- Update to version 20260904.a50a34d6:
+  * container_cleaner.py: Handle multibuild flavors separately
+
+-------------------------------------------------------------------
+Wed Sep 02 09:33:57 UTC 2026 - [email protected]
+
+- Update to version 20260902.9b3f47fc:
+  * check_source.py: Do not skip unchanged URLs
+
+-------------------------------------------------------------------
+Tue Sep 01 14:27:25 UTC 2026 - [email protected]
+
+- Update to version 20260901.eb52bd92:
+  * gocd: Enable productcompose pkglist-generation for Staging
+
+-------------------------------------------------------------------

Old:
----
  openSUSE-release-tools-20260824.b49927f7.obscpio

New:
----
  openSUSE-release-tools-20260911.6454091f.obscpio

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ openSUSE-release-tools.spec ++++++
--- /var/tmp/diff_new_pack.7z3nkk/_old  2026-09-18 22:08:32.856645441 +0200
+++ /var/tmp/diff_new_pack.7z3nkk/_new  2026-09-18 22:08:32.860645609 +0200
@@ -21,7 +21,7 @@
 %define announcer_filename factory-package-news
 %define services osrt-slsa.target [email protected] 
[email protected] [email protected] [email protected] 
[email protected] [email protected]
 Name:           openSUSE-release-tools
-Version:        20260824.b49927f7
+Version:        20260911.6454091f
 Release:        0
 Summary:        Tools to aid in staging and release work for openSUSE/SUSE
 License:        GPL-2.0-or-later AND MIT

++++++ _servicedata ++++++
--- /var/tmp/diff_new_pack.7z3nkk/_old  2026-09-18 22:08:32.928648459 +0200
+++ /var/tmp/diff_new_pack.7z3nkk/_new  2026-09-18 22:08:32.937648836 +0200
@@ -1,7 +1,7 @@
 <servicedata>
   <service name="tar_scm">
     <param 
name="url">https://github.com/openSUSE/openSUSE-release-tools.git</param>
-    <param 
name="changesrevision">b49927f739ddffa0e29c91e0d74d9e5260de477d</param>
+    <param 
name="changesrevision">6454091f081b30022dd358bc361bd59079e8740b</param>
   </service>
 </servicedata>
 

++++++ openSUSE-release-tools-20260824.b49927f7.obscpio -> 
openSUSE-release-tools-20260911.6454091f.obscpio ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/openSUSE-release-tools-20260824.b49927f7/check_source.py 
new/openSUSE-release-tools-20260911.6454091f/check_source.py
--- old/openSUSE-release-tools-20260824.b49927f7/check_source.py        
2026-08-24 12:59:06.000000000 +0200
+++ new/openSUSE-release-tools-20260911.6454091f/check_source.py        
2026-09-11 09:40:33.000000000 +0200
@@ -702,26 +702,7 @@
 
         return True
 
-    def _snipe_out_existing_urls(self, old, directory, specs):
-        if not os.path.isdir(old):
-            return
-        oldsources = self._mentioned_sources(old, specs)
-        for spec in specs:
-            specfn = os.path.join(directory, spec)
-            nspecfn = specfn + '.new'
-            wf = open(nspecfn, 'w')
-            with open(specfn) as rf:
-                for line in rf:
-                    m = re.match(r'(Source[0-9]*\s*):\s*(.*)$', line)
-                    if m and m.group(2) in oldsources:
-                        wf.write(m.group(1) + ":" + 
os.path.basename(m.group(2)) + "\n")
-                        continue
-                    wf.write(line)
-            wf.close()
-            os.rename(nspecfn, specfn)
-
     def check_urls(self, old, directory, specs):
-        self._snipe_out_existing_urls(old, directory, specs)
         oldcwd = os.getcwd()
         with tempfile.TemporaryDirectory() as tmpdir:
             os.chdir(directory)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/openSUSE-release-tools-20260824.b49927f7/container_cleaner.py 
new/openSUSE-release-tools-20260911.6454091f/container_cleaner.py
--- old/openSUSE-release-tools-20260824.b49927f7/container_cleaner.py   
2026-08-24 12:59:06.000000000 +0200
+++ new/openSUSE-release-tools-20260911.6454091f/container_cleaner.py   
2026-09-11 09:40:33.000000000 +0200
@@ -8,7 +8,7 @@
 import ToolBase
 import sys
 import re
-from collections import defaultdict
+from collections import defaultdict, namedtuple
 from lxml import etree as xml
 
 
@@ -27,94 +27,78 @@
         return xml.parse(self.retried_GET(url))
 
     def findSourcepkgsToDelete(self, project):
-        # Get a list of all images
-        srccontainers = self.getDirEntries(["source", project])
+        # Get a set of all srccontainers in the project
+        srccontainers = set(self.getDirEntries(["source", project]))
 
-        # Sort the released packages into buckets for each origin package:
-        # {"opensuse-tumbleweed-image": 
["opensuse-tumbleweed-image.20190402134201", ...]}
-        buckets = defaultdict(list)
-        regex_maintenance_release = re.compile(R"^(.+)\.[0-9]+$")
-        for srccontainer in srccontainers:
-            # Get the right bucket
-            match = regex_maintenance_release.match(srccontainer)
-            if match:
-                # Maintenance release
-                package = match.group(1)
-            else:
-                # Not renamed
-                package = srccontainer
-
-            if srccontainer not in buckets[package]:
-                buckets[package] += [srccontainer]
-
-        for package in buckets:
-            # Sort each bucket: Newest provider first
-            buckets[package].sort(reverse=True)
-            logging.debug("Found %d providers of %s", len(buckets[package]), 
package)
+        # List of all binaries in the project
+        resultlist = self.getBinaryList(project)
 
-        # Get a hash for sourcecontainer -> arch with binaries
-        # {"opensuse-tumbleweed-image.20190309164844": ["aarch64", "armv7l", 
"armv6l"],
-        # "kubic-pause-image.20190306124139": ["x86_64", "i586"], ... }
-        srccontainerarchs = defaultdict(list)
+        # The bot keeps five releases of each image alive. "Same image" is 
defined by
+        # having the same package name, flavor and architecture.
+        ImageKey = namedtuple("ProvidedImage", ["pkgname", "flavor", "arch"])
+
+        # A released image. maint_release kept as first tuple member to act 
for sorting.
+        ReleasedImage = namedtuple("ReleasedImage", ["maint_release", 
"buildcontainer", "srccontainer"])
+
+        # Sort the released packages into buckets for each image it provides:
+        # {ImageKey("opensuse-tumbleweed-image", "docker", "x86_64"):
+        #    [ReleasedImage(20190402134201, 
"container-image.20190402134201:docker", "container-image.20190402134201"), 
...]}
+        buckets = defaultdict(list)
 
-        resultlist = self.getBinaryList(project)
+        # Split a buildcontainer name like "sourcepkg.01234:flavor" into its 
parts
+        regex_buildcontainer = re.compile(R"^([^:]+)\.([0-9]+)(:[^:]+)?$")
 
-        regex_srccontainer = re.compile(R"^([^:]+)(:[^:]+)?$")
         for arch_result in resultlist.xpath("result"):
             arch = arch_result.get("arch")
 
             for binarylist in arch_result.xpath("binarylist"):
                 buildcontainer = binarylist.get("package")
-                if len(binarylist.xpath("binary")) > 0:
-                    match = regex_srccontainer.match(buildcontainer)
-                    if not match:
-                        raise Exception(f"Could not map {buildcontainer} to 
source container")
-
-                    srccontainer = match.group(1)
-                    if srccontainer not in srccontainers:
-                        raise Exception(f"Mapped {buildcontainer} to wrong 
source container ({srccontainer})")
+                if len(binarylist.xpath("binary")) == 0:
+                    continue
 
-                    logging.debug("%s provides binaries for %s", srccontainer, 
arch)
-                    srccontainerarchs[srccontainer] += [arch]
+                match = regex_buildcontainer.match(buildcontainer)
+                if not match:
+                    raise Exception(f"Could not parse {buildcontainer} as 
build container")
+
+                pkgname, maint_release, flavor = match.group(1, 2, 3)
+                srccontainer = f"{pkgname}.{maint_release}"
+                if srccontainer not in srccontainers:
+                    raise Exception(f"Mapped {buildcontainer} to wrong source 
container ({srccontainer})")
+
+                imgbucket = ImageKey(pkgname, flavor, arch)
+                logging.debug("%s provides binaries for %s through %s", 
buildcontainer, imgbucket, srccontainer)
+                buckets[imgbucket] += [ReleasedImage(maint_release, 
buildcontainer, srccontainer)]
+
+        # The list of srccontainers referenced by released images
+        seen_srccontainers = set([img.srccontainer for pkg in buckets for img 
in buckets[pkg]])
+        srccontainers_not_seen = set(srccontainers) - seen_srccontainers
+        if srccontainers_not_seen:
+            logging.warning(f"The following srccontainers have no binaries and 
will not be touched: {srccontainers_not_seen}")
+        else:
+            logging.debug("All srccontainers have binaries!")
 
         # Now go through each bucket and find out what doesn't contribute to 
the newest five
-        can_delete = []
+        srccontainers_referenced = set()
         for package in buckets:
-            # {"x86_64": 1, "aarch64": 2, ...}
-            archs_found = defaultdict(lambda: 0)
+            # Sort each bucket: Newest provider first
+            buckets[package].sort(reverse=True)
+            logging.debug("Found %d providers of %s", len(buckets[package]), 
package)
 
-            for srccontainer in buckets[package]:
-                contributes = False
-                for arch in srccontainerarchs[srccontainer]:
-                    if archs_found[arch] < 5:
-                        archs_found[arch] += 1
-                        contributes = True
-
-                if len(srccontainerarchs[srccontainer]) == 0:
-                    logging.warning("%s has no binaries (any flavor/any arch) 
- skipping", srccontainer)
-                elif contributes:
-                    logging.debug("%s contributes to %s", srccontainer, 
package)
-                else:
-                    logging.info("%s does not contribute", srccontainer)
-                    if len([count for count in archs_found.values() if count > 
0]) == 0:
-                        # If there are A, B, C and D, with only C and D 
providing binaries,
-                        # A and B aren't deleted because they have newer 
sources. This is
-                        # to avoid deleting something due to unforeseen 
circumstances, e.g.
-                        # OBS didn't copy the binaries yet.
-                        logging.warning("No newer provider found either, 
ignoring")
-                    else:
-                        can_delete += [srccontainer]
+            for released_image in buckets[package][:5]:
+                logging.debug(f"\t{released_image} needed")
+                srccontainers_referenced.add(released_image.srccontainer)
+            for released_image in buckets[package][5:]:
+                logging.debug(f"\t{released_image} no longer needed")
 
-        return can_delete
+        return seen_srccontainers - srccontainers_referenced
 
     def run(self, project):
         packages = self.findSourcepkgsToDelete(project)
 
         for package in packages:
             url = self.makeurl(["source", project, package])
-            if self.dryrun:
-                logging.info("DELETE %s", url)
-            else:
+            logging.info("DELETE %s", url)
+            if not self.dryrun:
                 osc.core.http_DELETE(url)
 
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/openSUSE-release-tools-20260824.b49927f7/dashboard/generate.py 
new/openSUSE-release-tools-20260911.6454091f/dashboard/generate.py
--- old/openSUSE-release-tools-20260824.b49927f7/dashboard/generate.py  
2026-08-24 12:59:06.000000000 +0200
+++ new/openSUSE-release-tools-20260911.6454091f/dashboard/generate.py  
2026-09-11 09:40:33.000000000 +0200
@@ -51,6 +51,14 @@
         'openqa_groupid': 75,
     },
     {
+        'name': 'openSUSE:Factory:LegacyARM',
+        'nick': 'Legacy ARM',
+        'download_url': 
'https://download.opensuse.org/ports/armv7hl/tumbleweed/iso/',
+        'openqa_group': 'openSUSE Tumbleweed Legacy ARM',
+        'openqa_version': 'Tumbleweed',
+        'openqa_groupid': 143,
+    },
+    {
         'name': 'openSUSE:Factory:PowerPC',
         'nick': 'Power',
         'download_url': 
'https://download.opensuse.org/ports/ppc/tumbleweed/iso/',
@@ -74,6 +82,14 @@
         'openqa_version': 'Tumbleweed',
         'openqa_groupid': 34,
     },
+    {
+        'name': 'devel:ARM:Factory:ARMv9',
+        'nick': 'ARMv9',
+        'download_url': 
'https://download.opensuse.org/repositories/devel:/ARM:/Factory:/ARMv9:/ToTest/images/iso/',
+        'openqa_group': 'Devel Tumbleweed ARMv9',
+        'openqa_version': 'Tumbleweed',
+        'openqa_groupid': 137,
+    },
 ]
 
 LEAP_PROJECTS = [
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/openSUSE-release-tools-20260824.b49927f7/gocd/pkglistgen.opensuse.gocd.yaml 
new/openSUSE-release-tools-20260911.6454091f/gocd/pkglistgen.opensuse.gocd.yaml
--- 
old/openSUSE-release-tools-20260824.b49927f7/gocd/pkglistgen.opensuse.gocd.yaml 
    2026-08-24 12:59:06.000000000 +0200
+++ 
new/openSUSE-release-tools-20260911.6454091f/gocd/pkglistgen.opensuse.gocd.yaml 
    2026-09-11 09:40:33.000000000 +0200
@@ -56,6 +56,14 @@
                   python3 -u ./pkglistgen.py -d -A https://api.opensuse.org 
update_and_solve -p openSUSE:Factory:LegacyX86 -s target 
--only-release-packages --force
                   python3 -u ./pkglistgen.py -d -A https://api.opensuse.org 
update_and_solve -p openSUSE:Factory:LegacyX86 -s target
                   python3 -u ./pkglistgen.py -d -A https://api.opensuse.org 
update_and_solve -p openSUSE:Factory:LegacyX86 -s target 
--engine=product_composer --force
+          openSUSE_Factory_LegacyARM_target:
+            resources:
+            - repo-checker
+            tasks:
+              - script: |
+                  python3 -u ./pkglistgen.py -d -A https://api.opensuse.org 
update_and_solve -p openSUSE:Factory:LegacyARM -s target 
--only-release-packages --force
+                  python3 -u ./pkglistgen.py -d -A https://api.opensuse.org 
update_and_solve -p openSUSE:Factory:LegacyARM -s target
+                  python3 -u ./pkglistgen.py -d -A https://api.opensuse.org 
update_and_solve -p openSUSE:Factory:LegacyARM -s target 
--engine=product_composer --force
           openSUSE_Factory_PowerPC:
             resources:
             - repo-checker
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/openSUSE-release-tools-20260824.b49927f7/gocd/pkglistgen.opensuse.gocd.yaml.erb
 
new/openSUSE-release-tools-20260911.6454091f/gocd/pkglistgen.opensuse.gocd.yaml.erb
--- 
old/openSUSE-release-tools-20260824.b49927f7/gocd/pkglistgen.opensuse.gocd.yaml.erb
 2026-08-24 12:59:06.000000000 +0200
+++ 
new/openSUSE-release-tools-20260911.6454091f/gocd/pkglistgen.opensuse.gocd.yaml.erb
 2026-09-11 09:40:33.000000000 +0200
@@ -16,7 +16,7 @@
         approval:
           type: manual
         jobs:
-<% ['openSUSE:Factory/target', 'openSUSE:Factory/ring1', 
'openSUSE:Factory:ARM/target', 'openSUSE:Factory:ARM/ring1', 
'openSUSE:Factory:LegacyX86/target', 'openSUSE:Factory:PowerPC', 
'openSUSE:Factory:zSystems', 'openSUSE:Factory:RISCV'].each do |project|
+<% ['openSUSE:Factory/target', 'openSUSE:Factory/ring1', 
'openSUSE:Factory:ARM/target', 'openSUSE:Factory:ARM/ring1', 
'openSUSE:Factory:LegacyX86/target', 'openSUSE:Factory:LegacyARM/target', 
'openSUSE:Factory:PowerPC', 'openSUSE:Factory:zSystems', 
'openSUSE:Factory:RISCV'].each do |project|
   project=project.split('/')
   name=project[0].gsub(':', '_')
   if project.size > 1
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/openSUSE-release-tools-20260824.b49927f7/gocd/pkglistgen_staging.gocd.yaml 
new/openSUSE-release-tools-20260911.6454091f/gocd/pkglistgen_staging.gocd.yaml
--- 
old/openSUSE-release-tools-20260824.b49927f7/gocd/pkglistgen_staging.gocd.yaml  
    2026-08-24 12:59:06.000000000 +0200
+++ 
new/openSUSE-release-tools-20260911.6454091f/gocd/pkglistgen_staging.gocd.yaml  
    2026-09-11 09:40:33.000000000 +0200
@@ -189,12 +189,26 @@
                 exit 1
               fi
 
+    - Update.000productcompose:
+        resources:
+          - repo-checker
+        tasks:
+          - script: |-
+              export PYTHONPATH=scripts
+              if ./scripts/pkglistgen.py --debug -A $STAGING_API 
update_and_solve --staging $STAGING_PROJECT --engine=product_composer --force; 
then
+                ./scripts/gocd/report-status.py -A $STAGING_API -p 
$STAGING_PROJECT -n packagelists -r standard -s success
+              else
+                ./scripts/gocd/report-status.py -A $STAGING_API -p 
$STAGING_PROJECT -n packagelists -r standard -s failure
+                exit 1
+              fi
+
     - Enable.images.repo:
         resources:
           - staging-bot
         tasks:
           - script: |-
               osc -A $STAGING_API api -X POST 
"/source/$STAGING_PROJECT?cmd=remove_flag&repository=images&flag=build"
+              osc -A $STAGING_API api -X POST 
"/source/$STAGING_PROJECT?cmd=remove_flag&repository=product&flag=build"
               export PYTHONPATH=$PWD/scripts
               while osc -A $STAGING_API api 
"/build/$STAGING_PROJECT/_result?view=summary&repository=images" | grep 
'dirty=.true.'; do
                 sleep 60
@@ -255,12 +269,26 @@
                 exit 1
               fi
 
+    - Update.000productcompose:
+        resources:
+          - repo-checker
+        tasks:
+          - script: |-
+              export PYTHONPATH=scripts
+              if ./scripts/pkglistgen.py --debug -A $STAGING_API 
update_and_solve --staging $STAGING_PROJECT --engine=product_composer --force; 
then
+                ./scripts/gocd/report-status.py -A $STAGING_API -p 
$STAGING_PROJECT -n packagelists -r standard -s success
+              else
+                ./scripts/gocd/report-status.py -A $STAGING_API -p 
$STAGING_PROJECT -n packagelists -r standard -s failure
+                exit 1
+              fi
+
     - Enable.images.repo:
         resources:
           - staging-bot
         tasks:
           - script: |-
               osc -A $STAGING_API api -X POST 
"/source/$STAGING_PROJECT?cmd=remove_flag&repository=images&flag=build"
+              osc -A $STAGING_API api -X POST 
"/source/$STAGING_PROJECT?cmd=remove_flag&repository=product&flag=build"
               export PYTHONPATH=$PWD/scripts
               while osc -A $STAGING_API api 
"/build/$STAGING_PROJECT/_result?view=summary&repository=images" | grep 
'dirty=.true.'; do
                 sleep 60
@@ -321,12 +349,26 @@
                 exit 1
               fi
 
+    - Update.000productcompose:
+        resources:
+          - repo-checker
+        tasks:
+          - script: |-
+              export PYTHONPATH=scripts
+              if ./scripts/pkglistgen.py --debug -A $STAGING_API 
update_and_solve --staging $STAGING_PROJECT --engine=product_composer --force; 
then
+                ./scripts/gocd/report-status.py -A $STAGING_API -p 
$STAGING_PROJECT -n packagelists -r standard -s success
+              else
+                ./scripts/gocd/report-status.py -A $STAGING_API -p 
$STAGING_PROJECT -n packagelists -r standard -s failure
+                exit 1
+              fi
+
     - Enable.images.repo:
         resources:
           - staging-bot
         tasks:
           - script: |-
               osc -A $STAGING_API api -X POST 
"/source/$STAGING_PROJECT?cmd=remove_flag&repository=images&flag=build"
+              osc -A $STAGING_API api -X POST 
"/source/$STAGING_PROJECT?cmd=remove_flag&repository=product&flag=build"
               export PYTHONPATH=$PWD/scripts
               while osc -A $STAGING_API api 
"/build/$STAGING_PROJECT/_result?view=summary&repository=images" | grep 
'dirty=.true.'; do
                 sleep 60
@@ -387,12 +429,26 @@
                 exit 1
               fi
 
+    - Update.000productcompose:
+        resources:
+          - repo-checker
+        tasks:
+          - script: |-
+              export PYTHONPATH=scripts
+              if ./scripts/pkglistgen.py --debug -A $STAGING_API 
update_and_solve --staging $STAGING_PROJECT --engine=product_composer --force; 
then
+                ./scripts/gocd/report-status.py -A $STAGING_API -p 
$STAGING_PROJECT -n packagelists -r standard -s success
+              else
+                ./scripts/gocd/report-status.py -A $STAGING_API -p 
$STAGING_PROJECT -n packagelists -r standard -s failure
+                exit 1
+              fi
+
     - Enable.images.repo:
         resources:
           - staging-bot
         tasks:
           - script: |-
               osc -A $STAGING_API api -X POST 
"/source/$STAGING_PROJECT?cmd=remove_flag&repository=images&flag=build"
+              osc -A $STAGING_API api -X POST 
"/source/$STAGING_PROJECT?cmd=remove_flag&repository=product&flag=build"
               export PYTHONPATH=$PWD/scripts
               while osc -A $STAGING_API api 
"/build/$STAGING_PROJECT/_result?view=summary&repository=images" | grep 
'dirty=.true.'; do
                 sleep 60
@@ -453,12 +509,26 @@
                 exit 1
               fi
 
+    - Update.000productcompose:
+        resources:
+          - repo-checker
+        tasks:
+          - script: |-
+              export PYTHONPATH=scripts
+              if ./scripts/pkglistgen.py --debug -A $STAGING_API 
update_and_solve --staging $STAGING_PROJECT --engine=product_composer --force; 
then
+                ./scripts/gocd/report-status.py -A $STAGING_API -p 
$STAGING_PROJECT -n packagelists -r standard -s success
+              else
+                ./scripts/gocd/report-status.py -A $STAGING_API -p 
$STAGING_PROJECT -n packagelists -r standard -s failure
+                exit 1
+              fi
+
     - Enable.images.repo:
         resources:
           - staging-bot
         tasks:
           - script: |-
               osc -A $STAGING_API api -X POST 
"/source/$STAGING_PROJECT?cmd=remove_flag&repository=images&flag=build"
+              osc -A $STAGING_API api -X POST 
"/source/$STAGING_PROJECT?cmd=remove_flag&repository=product&flag=build"
               export PYTHONPATH=$PWD/scripts
               while osc -A $STAGING_API api 
"/build/$STAGING_PROJECT/_result?view=summary&repository=images" | grep 
'dirty=.true.'; do
                 sleep 60
@@ -519,12 +589,26 @@
                 exit 1
               fi
 
+    - Update.000productcompose:
+        resources:
+          - repo-checker
+        tasks:
+          - script: |-
+              export PYTHONPATH=scripts
+              if ./scripts/pkglistgen.py --debug -A $STAGING_API 
update_and_solve --staging $STAGING_PROJECT --engine=product_composer --force; 
then
+                ./scripts/gocd/report-status.py -A $STAGING_API -p 
$STAGING_PROJECT -n packagelists -r standard -s success
+              else
+                ./scripts/gocd/report-status.py -A $STAGING_API -p 
$STAGING_PROJECT -n packagelists -r standard -s failure
+                exit 1
+              fi
+
     - Enable.images.repo:
         resources:
           - staging-bot
         tasks:
           - script: |-
               osc -A $STAGING_API api -X POST 
"/source/$STAGING_PROJECT?cmd=remove_flag&repository=images&flag=build"
+              osc -A $STAGING_API api -X POST 
"/source/$STAGING_PROJECT?cmd=remove_flag&repository=product&flag=build"
               export PYTHONPATH=$PWD/scripts
               while osc -A $STAGING_API api 
"/build/$STAGING_PROJECT/_result?view=summary&repository=images" | grep 
'dirty=.true.'; do
                 sleep 60
@@ -585,12 +669,26 @@
                 exit 1
               fi
 
+    - Update.000productcompose:
+        resources:
+          - repo-checker
+        tasks:
+          - script: |-
+              export PYTHONPATH=scripts
+              if ./scripts/pkglistgen.py --debug -A $STAGING_API 
update_and_solve --staging $STAGING_PROJECT --engine=product_composer --force; 
then
+                ./scripts/gocd/report-status.py -A $STAGING_API -p 
$STAGING_PROJECT -n packagelists -r standard -s success
+              else
+                ./scripts/gocd/report-status.py -A $STAGING_API -p 
$STAGING_PROJECT -n packagelists -r standard -s failure
+                exit 1
+              fi
+
     - Enable.images.repo:
         resources:
           - staging-bot
         tasks:
           - script: |-
               osc -A $STAGING_API api -X POST 
"/source/$STAGING_PROJECT?cmd=remove_flag&repository=images&flag=build"
+              osc -A $STAGING_API api -X POST 
"/source/$STAGING_PROJECT?cmd=remove_flag&repository=product&flag=build"
               export PYTHONPATH=$PWD/scripts
               while osc -A $STAGING_API api 
"/build/$STAGING_PROJECT/_result?view=summary&repository=images" | grep 
'dirty=.true.'; do
                 sleep 60
@@ -651,12 +749,26 @@
                 exit 1
               fi
 
+    - Update.000productcompose:
+        resources:
+          - repo-checker
+        tasks:
+          - script: |-
+              export PYTHONPATH=scripts
+              if ./scripts/pkglistgen.py --debug -A $STAGING_API 
update_and_solve --staging $STAGING_PROJECT --engine=product_composer --force; 
then
+                ./scripts/gocd/report-status.py -A $STAGING_API -p 
$STAGING_PROJECT -n packagelists -r standard -s success
+              else
+                ./scripts/gocd/report-status.py -A $STAGING_API -p 
$STAGING_PROJECT -n packagelists -r standard -s failure
+                exit 1
+              fi
+
     - Enable.images.repo:
         resources:
           - staging-bot
         tasks:
           - script: |-
               osc -A $STAGING_API api -X POST 
"/source/$STAGING_PROJECT?cmd=remove_flag&repository=images&flag=build"
+              osc -A $STAGING_API api -X POST 
"/source/$STAGING_PROJECT?cmd=remove_flag&repository=product&flag=build"
               export PYTHONPATH=$PWD/scripts
               while osc -A $STAGING_API api 
"/build/$STAGING_PROJECT/_result?view=summary&repository=images" | grep 
'dirty=.true.'; do
                 sleep 60
@@ -717,12 +829,26 @@
                 exit 1
               fi
 
+    - Update.000productcompose:
+        resources:
+          - repo-checker
+        tasks:
+          - script: |-
+              export PYTHONPATH=scripts
+              if ./scripts/pkglistgen.py --debug -A $STAGING_API 
update_and_solve --staging $STAGING_PROJECT --engine=product_composer --force; 
then
+                ./scripts/gocd/report-status.py -A $STAGING_API -p 
$STAGING_PROJECT -n packagelists -r standard -s success
+              else
+                ./scripts/gocd/report-status.py -A $STAGING_API -p 
$STAGING_PROJECT -n packagelists -r standard -s failure
+                exit 1
+              fi
+
     - Enable.images.repo:
         resources:
           - staging-bot
         tasks:
           - script: |-
               osc -A $STAGING_API api -X POST 
"/source/$STAGING_PROJECT?cmd=remove_flag&repository=images&flag=build"
+              osc -A $STAGING_API api -X POST 
"/source/$STAGING_PROJECT?cmd=remove_flag&repository=product&flag=build"
               export PYTHONPATH=$PWD/scripts
               while osc -A $STAGING_API api 
"/build/$STAGING_PROJECT/_result?view=summary&repository=images" | grep 
'dirty=.true.'; do
                 sleep 60
@@ -783,12 +909,26 @@
                 exit 1
               fi
 
+    - Update.000productcompose:
+        resources:
+          - repo-checker
+        tasks:
+          - script: |-
+              export PYTHONPATH=scripts
+              if ./scripts/pkglistgen.py --debug -A $STAGING_API 
update_and_solve --staging $STAGING_PROJECT --engine=product_composer --force; 
then
+                ./scripts/gocd/report-status.py -A $STAGING_API -p 
$STAGING_PROJECT -n packagelists -r standard -s success
+              else
+                ./scripts/gocd/report-status.py -A $STAGING_API -p 
$STAGING_PROJECT -n packagelists -r standard -s failure
+                exit 1
+              fi
+
     - Enable.images.repo:
         resources:
           - staging-bot
         tasks:
           - script: |-
               osc -A $STAGING_API api -X POST 
"/source/$STAGING_PROJECT?cmd=remove_flag&repository=images&flag=build"
+              osc -A $STAGING_API api -X POST 
"/source/$STAGING_PROJECT?cmd=remove_flag&repository=product&flag=build"
               export PYTHONPATH=$PWD/scripts
               while osc -A $STAGING_API api 
"/build/$STAGING_PROJECT/_result?view=summary&repository=images" | grep 
'dirty=.true.'; do
                 sleep 60
@@ -849,12 +989,26 @@
                 exit 1
               fi
 
+    - Update.000productcompose:
+        resources:
+          - repo-checker
+        tasks:
+          - script: |-
+              export PYTHONPATH=scripts
+              if ./scripts/pkglistgen.py --debug -A $STAGING_API 
update_and_solve --staging $STAGING_PROJECT --engine=product_composer --force; 
then
+                ./scripts/gocd/report-status.py -A $STAGING_API -p 
$STAGING_PROJECT -n packagelists -r standard -s success
+              else
+                ./scripts/gocd/report-status.py -A $STAGING_API -p 
$STAGING_PROJECT -n packagelists -r standard -s failure
+                exit 1
+              fi
+
     - Enable.images.repo:
         resources:
           - staging-bot
         tasks:
           - script: |-
               osc -A $STAGING_API api -X POST 
"/source/$STAGING_PROJECT?cmd=remove_flag&repository=images&flag=build"
+              osc -A $STAGING_API api -X POST 
"/source/$STAGING_PROJECT?cmd=remove_flag&repository=product&flag=build"
               export PYTHONPATH=$PWD/scripts
               while osc -A $STAGING_API api 
"/build/$STAGING_PROJECT/_result?view=summary&repository=images" | grep 
'dirty=.true.'; do
                 sleep 60
@@ -915,12 +1069,26 @@
                 exit 1
               fi
 
+    - Update.000productcompose:
+        resources:
+          - repo-checker
+        tasks:
+          - script: |-
+              export PYTHONPATH=scripts
+              if ./scripts/pkglistgen.py --debug -A $STAGING_API 
update_and_solve --staging $STAGING_PROJECT --engine=product_composer --force; 
then
+                ./scripts/gocd/report-status.py -A $STAGING_API -p 
$STAGING_PROJECT -n packagelists -r standard -s success
+              else
+                ./scripts/gocd/report-status.py -A $STAGING_API -p 
$STAGING_PROJECT -n packagelists -r standard -s failure
+                exit 1
+              fi
+
     - Enable.images.repo:
         resources:
           - staging-bot
         tasks:
           - script: |-
               osc -A $STAGING_API api -X POST 
"/source/$STAGING_PROJECT?cmd=remove_flag&repository=images&flag=build"
+              osc -A $STAGING_API api -X POST 
"/source/$STAGING_PROJECT?cmd=remove_flag&repository=product&flag=build"
               export PYTHONPATH=$PWD/scripts
               while osc -A $STAGING_API api 
"/build/$STAGING_PROJECT/_result?view=summary&repository=images" | grep 
'dirty=.true.'; do
                 sleep 60
@@ -981,12 +1149,26 @@
                 exit 1
               fi
 
+    - Update.000productcompose:
+        resources:
+          - repo-checker
+        tasks:
+          - script: |-
+              export PYTHONPATH=scripts
+              if ./scripts/pkglistgen.py --debug -A $STAGING_API 
update_and_solve --staging $STAGING_PROJECT --engine=product_composer --force; 
then
+                ./scripts/gocd/report-status.py -A $STAGING_API -p 
$STAGING_PROJECT -n packagelists -r standard -s success
+              else
+                ./scripts/gocd/report-status.py -A $STAGING_API -p 
$STAGING_PROJECT -n packagelists -r standard -s failure
+                exit 1
+              fi
+
     - Enable.images.repo:
         resources:
           - staging-bot
         tasks:
           - script: |-
               osc -A $STAGING_API api -X POST 
"/source/$STAGING_PROJECT?cmd=remove_flag&repository=images&flag=build"
+              osc -A $STAGING_API api -X POST 
"/source/$STAGING_PROJECT?cmd=remove_flag&repository=product&flag=build"
               export PYTHONPATH=$PWD/scripts
               while osc -A $STAGING_API api 
"/build/$STAGING_PROJECT/_result?view=summary&repository=images" | grep 
'dirty=.true.'; do
                 sleep 60
@@ -1047,12 +1229,26 @@
                 exit 1
               fi
 
+    - Update.000productcompose:
+        resources:
+          - repo-checker
+        tasks:
+          - script: |-
+              export PYTHONPATH=scripts
+              if ./scripts/pkglistgen.py --debug -A $STAGING_API 
update_and_solve --staging $STAGING_PROJECT --engine=product_composer --force; 
then
+                ./scripts/gocd/report-status.py -A $STAGING_API -p 
$STAGING_PROJECT -n packagelists -r standard -s success
+              else
+                ./scripts/gocd/report-status.py -A $STAGING_API -p 
$STAGING_PROJECT -n packagelists -r standard -s failure
+                exit 1
+              fi
+
     - Enable.images.repo:
         resources:
           - staging-bot
         tasks:
           - script: |-
               osc -A $STAGING_API api -X POST 
"/source/$STAGING_PROJECT?cmd=remove_flag&repository=images&flag=build"
+              osc -A $STAGING_API api -X POST 
"/source/$STAGING_PROJECT?cmd=remove_flag&repository=product&flag=build"
               export PYTHONPATH=$PWD/scripts
               while osc -A $STAGING_API api 
"/build/$STAGING_PROJECT/_result?view=summary&repository=images" | grep 
'dirty=.true.'; do
                 sleep 60
@@ -1113,12 +1309,26 @@
                 exit 1
               fi
 
+    - Update.000productcompose:
+        resources:
+          - repo-checker
+        tasks:
+          - script: |-
+              export PYTHONPATH=scripts
+              if ./scripts/pkglistgen.py --debug -A $STAGING_API 
update_and_solve --staging $STAGING_PROJECT --engine=product_composer --force; 
then
+                ./scripts/gocd/report-status.py -A $STAGING_API -p 
$STAGING_PROJECT -n packagelists -r standard -s success
+              else
+                ./scripts/gocd/report-status.py -A $STAGING_API -p 
$STAGING_PROJECT -n packagelists -r standard -s failure
+                exit 1
+              fi
+
     - Enable.images.repo:
         resources:
           - staging-bot
         tasks:
           - script: |-
               osc -A $STAGING_API api -X POST 
"/source/$STAGING_PROJECT?cmd=remove_flag&repository=images&flag=build"
+              osc -A $STAGING_API api -X POST 
"/source/$STAGING_PROJECT?cmd=remove_flag&repository=product&flag=build"
               export PYTHONPATH=$PWD/scripts
               while osc -A $STAGING_API api 
"/build/$STAGING_PROJECT/_result?view=summary&repository=images" | grep 
'dirty=.true.'; do
                 sleep 60
@@ -1179,12 +1389,26 @@
                 exit 1
               fi
 
+    - Update.000productcompose:
+        resources:
+          - repo-checker
+        tasks:
+          - script: |-
+              export PYTHONPATH=scripts
+              if ./scripts/pkglistgen.py --debug -A $STAGING_API 
update_and_solve --staging $STAGING_PROJECT --engine=product_composer --force; 
then
+                ./scripts/gocd/report-status.py -A $STAGING_API -p 
$STAGING_PROJECT -n packagelists -r standard -s success
+              else
+                ./scripts/gocd/report-status.py -A $STAGING_API -p 
$STAGING_PROJECT -n packagelists -r standard -s failure
+                exit 1
+              fi
+
     - Enable.images.repo:
         resources:
           - staging-bot
         tasks:
           - script: |-
               osc -A $STAGING_API api -X POST 
"/source/$STAGING_PROJECT?cmd=remove_flag&repository=images&flag=build"
+              osc -A $STAGING_API api -X POST 
"/source/$STAGING_PROJECT?cmd=remove_flag&repository=product&flag=build"
               export PYTHONPATH=$PWD/scripts
               while osc -A $STAGING_API api 
"/build/$STAGING_PROJECT/_result?view=summary&repository=images" | grep 
'dirty=.true.'; do
                 sleep 60
@@ -1245,12 +1469,26 @@
                 exit 1
               fi
 
+    - Update.000productcompose:
+        resources:
+          - repo-checker
+        tasks:
+          - script: |-
+              export PYTHONPATH=scripts
+              if ./scripts/pkglistgen.py --debug -A $STAGING_API 
update_and_solve --staging $STAGING_PROJECT --engine=product_composer --force; 
then
+                ./scripts/gocd/report-status.py -A $STAGING_API -p 
$STAGING_PROJECT -n packagelists -r standard -s success
+              else
+                ./scripts/gocd/report-status.py -A $STAGING_API -p 
$STAGING_PROJECT -n packagelists -r standard -s failure
+                exit 1
+              fi
+
     - Enable.images.repo:
         resources:
           - staging-bot
         tasks:
           - script: |-
               osc -A $STAGING_API api -X POST 
"/source/$STAGING_PROJECT?cmd=remove_flag&repository=images&flag=build"
+              osc -A $STAGING_API api -X POST 
"/source/$STAGING_PROJECT?cmd=remove_flag&repository=product&flag=build"
               export PYTHONPATH=$PWD/scripts
               while osc -A $STAGING_API api 
"/build/$STAGING_PROJECT/_result?view=summary&repository=images" | grep 
'dirty=.true.'; do
                 sleep 60
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/openSUSE-release-tools-20260824.b49927f7/gocd/pkglistgen_staging.gocd.yaml.erb
 
new/openSUSE-release-tools-20260911.6454091f/gocd/pkglistgen_staging.gocd.yaml.erb
--- 
old/openSUSE-release-tools-20260824.b49927f7/gocd/pkglistgen_staging.gocd.yaml.erb
  2026-08-24 12:59:06.000000000 +0200
+++ 
new/openSUSE-release-tools-20260911.6454091f/gocd/pkglistgen_staging.gocd.yaml.erb
  2026-09-11 09:40:33.000000000 +0200
@@ -80,12 +80,26 @@
                 exit 1
               fi
 
+    - Update.000productcompose:
+        resources:
+          - repo-checker
+        tasks:
+          - script: |-
+              export PYTHONPATH=scripts
+              if ./scripts/pkglistgen.py --debug -A $STAGING_API 
update_and_solve --staging $STAGING_PROJECT --engine=product_composer --force; 
then
+                ./scripts/gocd/report-status.py -A $STAGING_API -p 
$STAGING_PROJECT -n packagelists -r standard -s success
+              else
+                ./scripts/gocd/report-status.py -A $STAGING_API -p 
$STAGING_PROJECT -n packagelists -r standard -s failure
+                exit 1
+              fi
+
     - Enable.images.repo:
         resources:
           - staging-bot
         tasks:
           - script: |-
               osc -A $STAGING_API api -X POST 
"/source/$STAGING_PROJECT?cmd=remove_flag&repository=images&flag=build"
+              osc -A $STAGING_API api -X POST 
"/source/$STAGING_PROJECT?cmd=remove_flag&repository=product&flag=build"
               export PYTHONPATH=$PWD/scripts
               while osc -A $STAGING_API api 
"/build/$STAGING_PROJECT/_result?view=summary&repository=images" | grep 
'dirty=.true.'; do
                 sleep 60
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/openSUSE-release-tools-20260824.b49927f7/gocd/rebuild-trigger.gocd.yaml 
new/openSUSE-release-tools-20260911.6454091f/gocd/rebuild-trigger.gocd.yaml
--- old/openSUSE-release-tools-20260824.b49927f7/gocd/rebuild-trigger.gocd.yaml 
2026-08-24 12:59:06.000000000 +0200
+++ new/openSUSE-release-tools-20260911.6454091f/gocd/rebuild-trigger.gocd.yaml 
2026-09-11 09:40:33.000000000 +0200
@@ -40,6 +40,26 @@
           - script: |-
               echo "openSUSE:Factory:LegacyX86"
               ./project-installcheck.py --debug check --store 
home:repo-checker/rebuilds openSUSE:Factory:LegacyX86
+  Trigger.Rebuild.Factory.LegacyARM:
+    group: openSUSE.Checkers
+    lock_behavior: unlockWhenFinished
+    environment_variables:
+      OSC_CONFIG: /home/go/config/oscrc-factory-maintainer
+    materials:
+      script:
+        git: https://github.com/openSUSE/openSUSE-release-tools.git
+    timer:
+      spec: 0 0 * ? * *
+      only_on_changes: false
+    stages:
+    - Run:
+        approval: manual
+        resources:
+          - repo-checker
+        tasks:
+          - script: |-
+              echo "openSUSE:Factory:LegacyARM"
+              ./project-installcheck.py --debug check --store 
home:repo-checker/rebuilds openSUSE:Factory:LegacyARM
   Trigger.Rebuild.Factory.Power:
     group: openSUSE.Checkers
     lock_behavior: unlockWhenFinished
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/openSUSE-release-tools-20260824.b49927f7/gocd/totestmanager.gocd.yaml 
new/openSUSE-release-tools-20260911.6454091f/gocd/totestmanager.gocd.yaml
--- old/openSUSE-release-tools-20260824.b49927f7/gocd/totestmanager.gocd.yaml   
2026-08-24 12:59:06.000000000 +0200
+++ new/openSUSE-release-tools-20260911.6454091f/gocd/totestmanager.gocd.yaml   
2026-09-11 09:40:33.000000000 +0200
@@ -63,6 +63,27 @@
         - script: |-
             install -D /home/go/config/openqa-client.conf 
/home/go/.config/openqa/client.conf
             scripts/totest-manager.py -A https://api.opensuse.org --debug run 
openSUSE:Factory:LegacyX86
+  TTM.Factory_LegacyARM:
+    group: openSUSE.Checkers
+    lock_behavior: unlockWhenFinished
+    environment_variables:
+      OSC_CONFIG: /home/go/config/oscrc-totest-manager
+    materials:
+      script:
+        git: https://github.com/openSUSE/openSUSE-release-tools.git
+        destination: scripts
+    timer:
+      spec: 0 */15 * ? * *
+      only_on_changes: false
+    stages:
+    - Run:
+        approval: manual
+        resources:
+        - staging-bot
+        tasks:
+        - script: |-
+            install -D /home/go/config/openqa-client.conf 
/home/go/.config/openqa/client.conf
+            scripts/totest-manager.py -A https://api.opensuse.org --debug run 
openSUSE:Factory:LegacyARM
   TTM.Factory_PowerPC:
     group: openSUSE.Checkers
     lock_behavior: unlockWhenFinished
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/openSUSE-release-tools-20260824.b49927f7/gocd/totestmanager.gocd.yaml.erb 
new/openSUSE-release-tools-20260911.6454091f/gocd/totestmanager.gocd.yaml.erb
--- 
old/openSUSE-release-tools-20260824.b49927f7/gocd/totestmanager.gocd.yaml.erb   
    2026-08-24 12:59:06.000000000 +0200
+++ 
new/openSUSE-release-tools-20260911.6454091f/gocd/totestmanager.gocd.yaml.erb   
    2026-09-11 09:40:33.000000000 +0200
@@ -4,6 +4,7 @@
       openSUSE:Factory
       openSUSE:Factory:ARM
       openSUSE:Factory:LegacyX86
+      openSUSE:Factory:LegacyARM
       openSUSE:Factory:PowerPC
       openSUSE:Factory:RISCV
       openSUSE:Factory:zSystems
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/openSUSE-release-tools-20260824.b49927f7/osclib/accept_command.py 
new/openSUSE-release-tools-20260911.6454091f/osclib/accept_command.py
--- old/openSUSE-release-tools-20260824.b49927f7/osclib/accept_command.py       
2026-08-24 12:59:06.000000000 +0200
+++ new/openSUSE-release-tools-20260911.6454091f/osclib/accept_command.py       
2026-09-11 09:40:33.000000000 +0200
@@ -275,12 +275,17 @@
 
         self.update_version_attribute(project, curr_version)
 
-        ports_prjs = ['ARM', 'LegacyX86', 'PowerPC', 'RISCV', 'zSystems']
+        ports_prjs = ['ARM', 'LegacyX86', 'LegacyARM', 'PowerPC', 'RISCV', 
'zSystems']
         for ports in ports_prjs:
             project = self.api.project + ':' + ports
             if self.api.item_exists(project):
                 self.update_version_attribute(project, curr_version)
 
+        # Also update devel:ARM:Factory:ARMv9
+        project = 'devel:ARM:Factory:ARMv9'
+        if self.api.item_exists(project):
+            self.update_version_attribute(project, curr_version)
+
     def sync_buildfailures(self):
         """
         Trigger rebuild of packages that failed build in either
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/openSUSE-release-tools-20260824.b49927f7/tests/check_source_tests.py 
new/openSUSE-release-tools-20260911.6454091f/tests/check_source_tests.py
--- old/openSUSE-release-tools-20260824.b49927f7/tests/check_source_tests.py    
2026-08-24 12:59:06.000000000 +0200
+++ new/openSUSE-release-tools-20260911.6454091f/tests/check_source_tests.py    
2026-09-11 09:40:33.000000000 +0200
@@ -386,7 +386,7 @@
 
     @pytest.mark.usefixtures("default_config")
     def test_existing_source_urls(self):
-        """Accepts invalid source URLs if previously present"""
+        """Refuses invalid source URLs even if previously present"""
         self._setup_devel_project(devel_files='blowfish-with-urls', 
target_files='blowfish-with-existing-url')
 
         req_id = self.wf.create_submit_request(self.devel_package.project,
@@ -397,7 +397,10 @@
         self.review_bot.set_request_ids([req_id])
         self.review_bot.check_requests()
 
-        self.assertReview(req_id, by_user=(self.bot_user, 'accepted'))
+        # not declined but not accepted either
+        review = self.assertReview(req_id, by_user=(self.bot_user, 'new'))
+        self.assertIn("Source URLs are not valid. Try `osc service runall 
download_files`.", review.comment)
+        self.assertIn("ERROR: Failed to download 
\"https://example.com/blowfish-1.tar.gz\"";, review.comment)
 
     @pytest.mark.usefixtures("default_config")
     def test_two_patches_in_one_line(self):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/openSUSE-release-tools-20260824.b49927f7/tests/container_cleaner_tests.py 
new/openSUSE-release-tools-20260911.6454091f/tests/container_cleaner_tests.py
--- 
old/openSUSE-release-tools-20260824.b49927f7/tests/container_cleaner_tests.py   
    2026-08-24 12:59:06.000000000 +0200
+++ 
new/openSUSE-release-tools-20260911.6454091f/tests/container_cleaner_tests.py   
    2026-09-11 09:40:33.000000000 +0200
@@ -6,6 +6,7 @@
 
 class MockedContainerCleaner(ContainerCleaner):
     def __init__(self, container_arch_map):
+        super().__init__()
         self.container_arch_map = container_arch_map
 
     def getDirEntries(self, path):
@@ -43,7 +44,7 @@
 class TestContainerCleaner(unittest.TestCase):
     def doTest(self, container_arch_map, to_be_deleted_exp):
         cleaner = MockedContainerCleaner(container_arch_map)
-        to_be_deleted = cleaner.findSourcepkgsToDelete("mock:prj")
+        to_be_deleted = list(cleaner.findSourcepkgsToDelete("mock:prj"))
         to_be_deleted.sort()
         self.assertEqual(to_be_deleted, to_be_deleted_exp)
 
@@ -57,7 +58,7 @@
 
     def test_nothingToDo(self):
         """Non-empty project, still do nothing"""
-        container_arch_map = {"c": ["i586", "x86_64"],
+        container_arch_map = {"c.00": ["i586", "x86_64"],
                               "c.01": ["i586"],
                               "c.02": ["x86_64"],
                               "c.04": ["i586", "x86_64"],
@@ -73,7 +74,7 @@
 
     def test_multiplePackages(self):
         """Multiple packages in one project"""
-        container_arch_map = {"c": ["i586", "x86_64"],
+        container_arch_map = {"c.00": ["i586", "x86_64"],
                               "c.01": ["i586"],
                               "c.02": ["x86_64"],
                               "c.03": [],
@@ -94,15 +95,14 @@
                               "e.56": ["i586"],
                               "e.57": ["i586"]}
 
-        to_be_deleted_exp = ["c", "c.01", "c.02", "c.04",
+        to_be_deleted_exp = ["c.00", "c.01", "c.02", "c.04",
                              "e.51"]
 
         return self.doTest(container_arch_map, to_be_deleted_exp)
 
     def test_multibuild(self):
-        """Packages using _multbuild.
-        There is no special handling for _multibuild - It's enough if any 
flavor has binaries."""
-        container_arch_map = {"c:docker": ["i586", "x86_64"],
+        """_multibuild flavors are treated like separate binaries"""
+        container_arch_map = {"c.00:docker": ["i586", "x86_64"],
                               "c.01:docker": ["i586"],
                               "c.02:lxc": ["x86_64"],
                               "c.03:docker": [],
@@ -114,7 +114,8 @@
                               "c.09:docker": ["i586", "x86_64"],
                               "c.10:docker": ["i586", "x86_64"],
                               "c.11:docker": [],
-                              "d.42:lxc": [], "d.43": [],
+                              "d.42:lxc": [],
+                              "d.43": [],
                               "e.51": ["i586"],
                               "e.52": ["aarch64"],
                               "e.53": ["i586"],
@@ -123,7 +124,45 @@
                               "e.56": ["i586"],
                               "e.57": ["i586"]}
 
-        to_be_deleted_exp = ["c", "c.01", "c.02", "c.04",
-                             "e.51"]
+        to_be_deleted_exp = ["c.00", "c.01"]
 
         return self.doTest(container_arch_map, to_be_deleted_exp)
+
+    def test_multibuild_independent(self):
+        """_multibuild flavors are treated like separate binaries"""
+        container_arch_map = {"f.0:a": ["x86_64"],
+                              "f.0:b": ["x86_64"],
+                              "f.1:b": ["x86_64"],
+                              "f.2:b": ["x86_64"],
+                              "f.3:b": ["x86_64"],
+                              "f.4:b": ["x86_64"],
+                              "f.5:b": ["x86_64"],
+                              "f.6:b": ["x86_64"]}
+
+        # f.0 is needed for f.0:a, keep it
+        to_be_deleted_exp = ["f.1"]
+
+        self.doTest(container_arch_map, to_be_deleted_exp)
+
+    def test_multibuild_manyflavors(self):
+        """Packages using _multbuild with many flavors
+        Ensure that every flavors is accounted for separately."""
+        container_arch_map = {}
+
+        # Generate five releases of a container with six flavors each.
+        # The flavors are released separately, so each flavor gets a new 
maintenance release
+        # number, i.e. c.00:fl0 and c.01:fl1 have binaries,
+        # while c.00:fl1-fl6, c.01:fl0 and c.01:fl2-6 do not.
+        relcounter = 0
+        for release in range(0, 4):
+            for flavor in range(0, 6):
+                relcounter = 6 * release + flavor
+                for allflavor in range(0, 6):
+                    container_arch_map[f"c.{relcounter}:fl{allflavor}"] = []
+
+                container_arch_map[f"c.{relcounter}:fl{flavor}"] = ["x86_64"]
+
+        # For each c:flX release, there are five binaries, thus nothing should 
get deleted.
+        to_be_deleted_exp = []
+
+        self.doTest(container_arch_map, to_be_deleted_exp)

++++++ openSUSE-release-tools.obsinfo ++++++
--- /var/tmp/diff_new_pack.7z3nkk/_old  2026-09-18 22:08:33.785684377 +0200
+++ /var/tmp/diff_new_pack.7z3nkk/_new  2026-09-18 22:08:33.793684712 +0200
@@ -1,5 +1,5 @@
 name: openSUSE-release-tools
-version: 20260824.b49927f7
-mtime: 1787569146
-commit: b49927f739ddffa0e29c91e0d74d9e5260de477d
+version: 20260911.6454091f
+mtime: 1789112433
+commit: 6454091f081b30022dd358bc361bd59079e8740b
 

Reply via email to