Hello community,

here is the log from the commit of package openSUSE-release-tools for 
openSUSE:Leap:15.2 checked in at 2020-04-03 15:52:37
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Leap:15.2/openSUSE-release-tools (Old)
 and      /work/SRC/openSUSE:Leap:15.2/.openSUSE-release-tools.new.3248 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "openSUSE-release-tools"

Fri Apr  3 15:52:37 2020 rev:306 rq:790943 version:20200325.77a14833

Changes:
--------
--- 
/work/SRC/openSUSE:Leap:15.2/openSUSE-release-tools/openSUSE-release-tools.changes
  2020-03-09 18:15:04.417431924 +0100
+++ 
/work/SRC/openSUSE:Leap:15.2/.openSUSE-release-tools.new.3248/openSUSE-release-tools.changes
        2020-04-03 15:52:47.241831441 +0200
@@ -1,0 +2,73 @@
+Wed Mar 25 16:28:21 UTC 2020 - [email protected]
+
+- Update to version 20200325.77a14833:
+  * Wipe all multibuild flavors for delete requests
+
+-------------------------------------------------------------------
+Tue Mar 24 08:33:11 UTC 2020 - [email protected]
+
+- Update to version 20200324.20869549:
+  * Allow to disable the check of delete requests per config
+
+-------------------------------------------------------------------
+Fri Mar 20 16:06:12 UTC 2020 - [email protected]
+
+- Update to version 20200320.2e3dc21c:
+  * Fix check_source for repository specific package names
+
+-------------------------------------------------------------------
+Thu Mar 19 16:17:27 UTC 2020 - [email protected]
+
+- Update to version 20200319.cdc271c2:
+  * Support 'required' field for packages
+
+-------------------------------------------------------------------
+Thu Mar 19 06:34:04 UTC 2020 - [email protected]
+
+- Update to version 20200319.37498292:
+  * Work around OBS issue 8994
+
+-------------------------------------------------------------------
+Wed Mar 18 13:04:40 UTC 2020 - [email protected]
+
+- Update to version 20200318.74ecff5c:
+  * Use the new API from openqa to sync the right repositories
+
+-------------------------------------------------------------------
+Tue Mar 17 06:38:30 UTC 2020 - [email protected]
+
+- Update to version 20200317.91ee0f41:
+  * Take the interesting repos from the output for now
+
+-------------------------------------------------------------------
+Mon Mar 16 14:53:54 UTC 2020 - [email protected]
+
+- Update to version 20200316.683bee4a:
+  * Sync script for obs_rsync
+
+-------------------------------------------------------------------
+Mon Mar 16 10:24:03 UTC 2020 - [email protected]
+
+- Update to version 20200316.08c8cd5d:
+  * No longer trigger obsrsync directly from rabbitmq messages
+
+-------------------------------------------------------------------
+Mon Mar 16 07:33:00 UTC 2020 - [email protected]
+
+- Update to version 20200316.ed7d3ce2:
+  * Adopt fixture to changes in obs' xml output
+  * Split the work done in rabbit-openqa into smaller chunks
+
+-------------------------------------------------------------------
+Tue Mar 10 11:12:08 UTC 2020 - [email protected]
+
+- Update to version 20200310.d98dd909:
+  * Switch metrics to use python3
+
+-------------------------------------------------------------------
+Tue Mar 10 09:50:19 UTC 2020 - [email protected]
+
+- Update to version 20200310.e25d3bfb:
+  * Add error message in case upload fails
+
+-------------------------------------------------------------------

Old:
----
  openSUSE-release-tools-20200306.ef1064e7.obscpio

New:
----
  openSUSE-release-tools-20200325.77a14833.obscpio

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

Other differences:
------------------
++++++ openSUSE-release-tools.spec ++++++
--- /var/tmp/diff_new_pack.RwcbiT/_old  2020-04-03 15:52:49.505834045 +0200
+++ /var/tmp/diff_new_pack.RwcbiT/_new  2020-04-03 15:52:49.509834050 +0200
@@ -20,7 +20,7 @@
 %define source_dir openSUSE-release-tools
 %define announcer_filename factory-package-news
 Name:           openSUSE-release-tools
-Version:        20200306.ef1064e7
+Version:        20200325.77a14833
 Release:        0
 Summary:        Tools to aid in staging and release work for openSUSE/SUSE
 License:        GPL-2.0-or-later AND MIT
@@ -166,11 +166,11 @@
 Suggests:       grafana
 %if 0%{?suse_version} > 1500
 Requires:       influxdb
-Requires:       python-influxdb
+Requires:       python3-influxdb
 Requires:       telegraf
 %else
 Suggests:       influxdb
-Suggests:       python-influxdb
+Suggests:       python3-influxdb
 Suggests:       telegraf
 %endif
 

++++++ _servicedata ++++++
--- /var/tmp/diff_new_pack.RwcbiT/_old  2020-04-03 15:52:49.541834087 +0200
+++ /var/tmp/diff_new_pack.RwcbiT/_new  2020-04-03 15:52:49.541834087 +0200
@@ -1,6 +1,6 @@
 <servicedata>
   <service name="tar_scm">
     <param 
name="url">https://github.com/openSUSE/openSUSE-release-tools.git</param>
-    <param 
name="changesrevision">3cd26236183eff49d71edf8de1aeb8649f7b62dd</param>
+    <param 
name="changesrevision">f28b520a92faa2d896dd253a8bd7319e6d634cee</param>
   </service>
 </servicedata>

++++++ openSUSE-release-tools-20200306.ef1064e7.obscpio -> 
openSUSE-release-tools-20200325.77a14833.obscpio ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/openSUSE-release-tools-20200306.ef1064e7/check_source.py 
new/openSUSE-release-tools-20200325.77a14833/check_source.py
--- old/openSUSE-release-tools-20200306.ef1064e7/check_source.py        
2020-03-06 13:26:18.000000000 +0100
+++ new/openSUSE-release-tools-20200325.77a14833/check_source.py        
2020-03-25 17:26:22.000000000 +0100
@@ -70,6 +70,42 @@
             # It might make sense to supersede maintbot, but for now.
             self.skip_add_reviews = True
 
+    def is_good_name(self, package, target_package):
+        self.logger.debug(f"is_good_name {package} <-> {target_package}")
+        if target_package is None:
+            # if the name doesn't matter, existance is all
+            return package is not None
+
+        return target_package == package
+
+    def package_source_parse(self, project, package, revision=None, 
target_package=None):
+        ret = self._package_source_parse(project, package, revision)
+
+        if self.is_good_name(ret['name'], target_package):
+            return ret
+
+        d = {}
+        for repo in osc.core.get_repositories_of_project(self.apiurl, project):
+            r = self._package_source_parse(project, package, revision, repo)
+            if r['name'] is not None:
+                d[r['name']] = r
+
+        if len(d) == 1:
+            # here is only one so use that
+            ret = d[next(iter(d))]
+        else:
+            # check if any name matches
+            self.logger.debug("found multiple names %s", ', '.join(d.keys()))
+            for n, r in d.items():
+                if n == target_package:
+                    ret = r
+                    break
+
+            if not self.is_good_name(ret['name'], target_package):
+                self.logger.error("none of the names matched")
+
+        return ret
+
     def check_source_submission(self, source_project, source_package, 
source_revision, target_project, target_package):
         super(CheckSource, self).check_source_submission(source_project, 
source_package, source_revision, target_project, target_package)
         self.target_project_config(target_project)
@@ -149,7 +185,7 @@
         os.rename(source_package, target_package)
         shutil.rmtree(os.path.join(target_package, '.osc'))
 
-        new_info = self.package_source_parse(source_project, source_package, 
source_revision)
+        new_info = self.package_source_parse(source_project, source_package, 
source_revision, target_package)
         if not new_info.get('filename', '').endswith('.kiwi') and 
new_info['name'] != target_package:
             shutil.rmtree(dir)
             self.review_messages['declined'] = "A package submitted as %s has 
to build as 'Name: %s' - found Name '%s'" % (target_package, target_package, 
new_info['name'])
@@ -312,34 +348,6 @@
 
         return ret
 
-    def package_source_parse(self, project, package, revision=None):
-        ret = self._package_source_parse(project, package, revision)
-
-        if ret['name'] is not None:
-            return ret
-
-        d = {}
-        for repo in osc.core.get_repositories_of_project(self.apiurl, project):
-            r = self._package_source_parse(project, package, revision, repo)
-            if r['name'] is not None:
-                d[r['name']] = r
-
-        if len(d) == 1:
-            # here is only one so use that
-            ret = d[next(iter(d))]
-        else:
-            # check if any name matches
-            self.logger.debug("found multiple names %s", ', '.join(d.keys()))
-            for n, r in d.items():
-                if n == package:
-                    ret = r
-                    break
-
-            if ret['name'] is None:
-                self.logger.error("none of the names matched")
-
-        return ret
-
     def only_changes(self):
         u = osc.core.makeurl(self.apiurl, ['request', self.request.reqid],
                              {'cmd': 'diff', 'view': 'xml'})
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/openSUSE-release-tools-20200306.ef1064e7/dist/package/openSUSE-release-tools.spec
 
new/openSUSE-release-tools-20200325.77a14833/dist/package/openSUSE-release-tools.spec
--- 
old/openSUSE-release-tools-20200306.ef1064e7/dist/package/openSUSE-release-tools.spec
       2020-03-06 13:26:18.000000000 +0100
+++ 
new/openSUSE-release-tools-20200325.77a14833/dist/package/openSUSE-release-tools.spec
       2020-03-25 17:26:22.000000000 +0100
@@ -166,11 +166,11 @@
 Suggests:       grafana
 %if 0%{?suse_version} > 1500
 Requires:       influxdb
-Requires:       python-influxdb
+Requires:       python3-influxdb
 Requires:       telegraf
 %else
 Suggests:       influxdb
-Suggests:       python-influxdb
+Suggests:       python3-influxdb
 Suggests:       telegraf
 %endif
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/openSUSE-release-tools-20200306.ef1064e7/gocd/monitors.gocd.yaml 
new/openSUSE-release-tools-20200325.77a14833/gocd/monitors.gocd.yaml
--- old/openSUSE-release-tools-20200306.ef1064e7/gocd/monitors.gocd.yaml        
2020-03-06 13:26:18.000000000 +0100
+++ new/openSUSE-release-tools-20200325.77a14833/gocd/monitors.gocd.yaml        
2020-03-25 17:26:22.000000000 +0100
@@ -65,6 +65,14 @@
         git: https://github.com/openSUSE/openSUSE-release-tools.git
         branch: master
         destination: scripts
+      repos:
+        git: git://botmaster.suse.de/suse-repos.git
+        branch: master
+        destination: repos
+      notifications:
+        git: git://botmaster.suse.de/suse-notifications.git
+        branch: master
+        destination: notifications
     stages:
     - Run:
         approval:
@@ -80,8 +88,7 @@
                 export PYTHONPATH=$PWD/scripts
                 git config --global user.email "[email protected]"
                 git config --global user.name "GoCD Repo Monitor"
-                git clone git://botmaster.suse.de/suse-repos.git
-                cd suse-repos
+                cd repos
                 ../scripts/gocd/rabbit-repoid.py -A https://api.suse.de 
SUSE:SLE
   openSUSE.Repo.Monitor:
     group: Monitors
@@ -95,6 +102,10 @@
         git: https://github.com/openSUSE/openSUSE-release-tools.git
         branch: master
         destination: scripts
+      repos:
+        git: git://botmaster.suse.de/opensuse-repos.git
+        branch: master
+        destination: repos
     stages:
     - Run:
         approval:
@@ -105,14 +116,78 @@
             resources:
             - monitor
             tasks:
+            - script: |-
+                export PYTHONPATH=$PWD/scripts
+                git config --global user.email "[email protected]"
+                git config --global user.name "GoCD Repo Monitor"
+                cd repos
+                ../scripts/gocd/rabbit-repoid.py -A https://api.opensuse.org 
openSUSE:Factory openSUSE:Leap Virtualization:WSL
+  openSUSE.ObsRsync:
+    group: Monitors
+    lock_behavior: unlockWhenFinished
+    environment_variables:
+      OSC_CONFIG: /home/go/config/oscrc-staging-bot
+    materials:
+      scripts:
+        git: https://github.com/openSUSE/openSUSE-release-tools.git
+        branch: master
+        destination: scripts
+      repos:
+        git: git://botmaster.suse.de/opensuse-repos.git
+        branch: master
+        destination: repos
+      notifications:
+        git: git://botmaster.suse.de/opensuse-notifications.git
+        branch: master
+        destination: notifications
+        whitelist:
+          - nothing
+    stages:
+    - Run:
+        jobs:
+          Run:
+            resources:
+            - staging-bot
+            tasks:
+            - script: |-
+                export PYTHONPATH=$PWD/scripts
+                git config --global user.email "[email protected]"
+                git config --global user.name "GoCD Repo Monitor"
+                scripts/gocd/notify-obs_rsync.py --openqa 
https://openqa.opensuse.org --repos repos --to notifications
+  SUSE.ObsRsync:
+    group: Monitors
+    lock_behavior: unlockWhenFinished
+    environment_variables:
+      OSC_CONFIG: /home/go/config/oscrc-staging-bot
+    materials:
+      scripts:
+        git: https://github.com/openSUSE/openSUSE-release-tools.git
+        branch: master
+        destination: scripts
+      repos:
+        git: git://botmaster.suse.de/suse-repos.git
+        branch: master
+        destination: repos
+      notifications:
+        git: git://botmaster.suse.de/suse-notifications.git
+        branch: master
+        destination: notifications
+        whitelist:
+          - nothing
+    stages:
+    - Run:
+        jobs:
+          Run:
+            resources:
+            - staging-bot
+            tasks:
             # endless loop
             - script: |-
                 export PYTHONPATH=$PWD/scripts
                 git config --global user.email "[email protected]"
                 git config --global user.name "GoCD Repo Monitor"
-                git clone git://botmaster.suse.de/opensuse-repos.git
-                cd opensuse-repos
-                ../scripts/gocd/rabbit-repoid.py -A https://api.opensuse.org 
openSUSE:Factory openSUSE:Leap
+                scripts/gocd/notify-obs_rsync.py --openqa 
https://openqa.suse.de --repos repos --to notifications
+
   openSUSE.OriginManagerUpdate:
     group: Monitors
     lock_behavior: unlockWhenFinished
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/openSUSE-release-tools-20200306.ef1064e7/gocd/notify-obs_rsync.py 
new/openSUSE-release-tools-20200325.77a14833/gocd/notify-obs_rsync.py
--- old/openSUSE-release-tools-20200306.ef1064e7/gocd/notify-obs_rsync.py       
1970-01-01 01:00:00.000000000 +0100
+++ new/openSUSE-release-tools-20200325.77a14833/gocd/notify-obs_rsync.py       
2020-03-25 17:26:22.000000000 +0100
@@ -0,0 +1,67 @@
+#!/usr/bin/python3
+
+import argparse
+import logging
+from shutil import copyfile
+import subprocess
+from os.path import basename
+import glob
+from openqa_client.client import OpenQA_Client
+from openqa_client.exceptions import ConnectionError, RequestError
+
+def old_filename(state):
+    return f'{args.repos}/{state}.yaml'
+
+def new_filename(state):
+    return f'{args.to}/{state}.yaml'
+
+def file_changed(state):
+    with open(old_filename(state), 'r') as old_file:
+        old_content = old_file.read()
+    try:
+        with open(new_filename(state), 'r') as new_file:
+            new_content = new_file.read()
+    except FileNotFoundError:
+        return True
+    return old_content != new_content
+
+def notify_project(openqa, state):
+    project, repository = state.split('_-_')
+    if not file_changed(state):
+        logger.debug(f'{state} did not change')
+        return
+    try:
+        openqa.openqa_request('PUT', 
'obs_rsync/{}/runs?repository={}'.format(project, repository), retries=0)
+    except RequestError as e:
+        logger.info("Got exception on syncing repository: {}".format(e))
+        return
+    copyfile(old_filename(state), new_filename(state))
+    subprocess.run(f'cd {args.to} && git add . && git commit -m "Update of 
{project}/{repository}" && git push', shell=True, check=True)
+
+if __name__ == '__main__':
+    parser = argparse.ArgumentParser(
+        description='Bot to sync openQA status to OBS')
+    parser.add_argument('--openqa', type=str, required=True, help='OpenQA URL')
+    parser.add_argument('--repos', type=str, required=True, help='Directory to 
read from')
+    parser.add_argument('--to', type=str, required=True, help='Directory to 
commit into')
+
+    global args
+    args = parser.parse_args()
+    global logger
+    logging.basicConfig(level=logging.DEBUG)
+    logger = logging.getLogger(__name__)
+
+    openqa = OpenQA_Client(server=args.openqa)
+
+    interesting_repos = dict()
+    list = openqa.openqa_request('GET', 'obs_rsync')
+    for repopair in list:
+        project, repository = repopair
+        interesting_repos[f'{project}_-_{repository}'] = 1
+
+    openqa = OpenQA_Client(server=args.openqa)
+    for state in glob.glob('{}/*.yaml'.format(args.repos)):
+        state = basename(state).replace('.yaml', '')
+        if not state in interesting_repos:
+            continue
+        notify_project(openqa, state)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/openSUSE-release-tools-20200306.ef1064e7/gocd/rabbit-openqa.py 
new/openSUSE-release-tools-20200325.77a14833/gocd/rabbit-openqa.py
--- old/openSUSE-release-tools-20200306.ef1064e7/gocd/rabbit-openqa.py  
2020-03-06 13:26:18.000000000 +0100
+++ new/openSUSE-release-tools-20200325.77a14833/gocd/rabbit-openqa.py  
2020-03-25 17:26:22.000000000 +0100
@@ -32,11 +32,13 @@
         self.replace_string = self.api.attribute_value_load('OpenQAMapping')
 
     def init(self):
-        for p in self.api.get_staging_projects():
-            if self.api.is_adi_project(p):
+        projects = set()
+        for project in self.api.get_staging_projects():
+            if self.api.is_adi_project(project):
                 continue
-            self.staging_projects[p] = self.initial_staging_state(p)
-            self.update_staging_status(p)
+            self.staging_projects[project] = 
self.initial_staging_state(project)
+            projects.add(project)
+        return projects
 
     def staging_letter(self, name):
         return name.split(':')[-1]
@@ -163,10 +165,11 @@
         self.amqp_prefix = amqp_prefix
         self.openqa_url = openqa_url
         self.openqa = OpenQA_Client(server=openqa_url)
+        self.projects_to_check = set()
 
     def routing_keys(self):
         ret = []
-        for suffix in ['.obs.repo.published', '.obs.repo.build_finished', 
'.openqa.job.done',
+        for suffix in ['.obs.repo.published', '.openqa.job.done',
                        '.openqa.job.create', '.openqa.job.restart']:
             ret.append(self.amqp_prefix + suffix)
         return ret
@@ -178,12 +181,33 @@
     def start_consuming(self):
         # now we are (re-)connected to the bus and need to fetch the
         # initial state
+        self.projects_to_check = set()
         for project in self.projects:
             self.logger.info('Fetching ISOs of %s', project.name)
-            project.init()
+            for sproj in project.init():
+                self.projects_to_check.add((project, sproj))
         self.logger.info('Finished fetching initial ISOs, listening')
         super(Listener, self).start_consuming()
 
+    def interval(self):
+        if len(self.projects_to_check):
+            return 5
+        return super(Listener, self).interval()
+
+    def check_some_projects(self):
+        count = 0
+        limit = 5
+        while len(self.projects_to_check):
+            project, staging = self.projects_to_check.pop()
+            project.update_staging_status(staging)
+            count += 1
+            if count >= limit:
+                return
+
+    def still_alive(self):
+        self.check_some_projects()
+        super(Listener, self).still_alive()
+
     def jobs_for_iso(self, iso):
         values = {
             'iso': iso,
@@ -210,15 +234,6 @@
         for p in self.projects:
             p.check_published_repo(str(payload['project']), 
str(payload['repo']), str(payload['buildid']))
 
-    def on_finished_repo(self, payload):
-        # notify openQA to sync the projects - the plugin will check itself it
-        # the project is to be synced. For now we notify about every 'images' 
repo
-        if payload['repo'] == 'images':
-            try:
-                self.openqa.openqa_request('PUT', 
'obs_rsync/{}/runs'.format(payload['project']), retries=0)
-            except RequestError as e:
-                self.logger.info("Got exception on syncing repository: 
{}".format(e))
-
     def on_openqa_job(self, iso):
         self.logger.debug('openqa_job_change %s', iso)
         for p in self.projects:
@@ -228,8 +243,6 @@
         self.acknowledge_message(method.delivery_tag)
         if method.routing_key == '{}.obs.repo.published'.format(amqp_prefix):
             self.on_published_repo(json.loads(body))
-        elif method.routing_key == 
'{}.obs.repo.build_finished'.format(amqp_prefix):
-            self.on_finished_repo(json.loads(body))
         elif re.search(r'.openqa.', method.routing_key):
             self.on_openqa_job(json.loads(body).get('ISO'))
         else:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/openSUSE-release-tools-20200306.ef1064e7/gocd/rabbit-repoid.py 
new/openSUSE-release-tools-20200325.77a14833/gocd/rabbit-repoid.py
--- old/openSUSE-release-tools-20200306.ef1064e7/gocd/rabbit-repoid.py  
2020-03-06 13:26:18.000000000 +0100
+++ new/openSUSE-release-tools-20200325.77a14833/gocd/rabbit-repoid.py  
2020-03-25 17:26:22.000000000 +0100
@@ -80,10 +80,11 @@
 
     def check_some_repos(self):
         count = 0
-        limit = 25
+        limit = 15
         while len(self.repositories_to_check):
             project, repository = self.repositories_to_check.pop()
             self.logger.debug(f"Check repo {project}/{repository}")
+            self.update_repo(project, repository)
             count += 1
             if count >= limit:
                 return
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/openSUSE-release-tools-20200306.ef1064e7/metrics.py 
new/openSUSE-release-tools-20200325.77a14833/metrics.py
--- old/openSUSE-release-tools-20200306.ef1064e7/metrics.py     2020-03-06 
13:26:18.000000000 +0100
+++ new/openSUSE-release-tools-20200325.77a14833/metrics.py     2020-03-25 
17:26:22.000000000 +0100
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/python3
 
 import argparse
 from collections import namedtuple
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/openSUSE-release-tools-20200306.ef1064e7/osclib/stagingapi.py 
new/openSUSE-release-tools-20200325.77a14833/osclib/stagingapi.py
--- old/openSUSE-release-tools-20200306.ef1064e7/osclib/stagingapi.py   
2020-03-06 13:26:18.000000000 +0100
+++ new/openSUSE-release-tools-20200325.77a14833/osclib/stagingapi.py   
2020-03-25 17:26:22.000000000 +0100
@@ -298,8 +298,7 @@
         :param destination_project: Destination project
         """
 
-        if not self.rm_from_prj(source_project, request_id=req_id,
-                         msg='Moved to {}'.format(destination_project)):
+        if not self.rm_from_prj(source_project, request_id=req_id):
             return False
 
         # Copy the package
@@ -518,7 +517,9 @@
                     # Supersedes request is from the same project
                     if request_new.find('./action/source').get('project') == 
request_old.find('./action/source').get('project'):
                         message = 'sr#{} has newer source and is from the same 
project'.format(request_new.get('id'))
-                        self.set_review(int(stage_info['rq_id']), 
stage_info['prj'], state='declined', msg=message)
+
+                        self.rm_from_prj(stage_info['prj'], 
request_id=stage_info['rq_id'])
+                        self.do_change_review_state(stage_info['rq_id'], 
'declined', by_group=self.cstaging_group, message=message)
                         return stage_info, None
                     # Ingore the new request pending manual review.
                     IgnoreCommand(self).perform([str(request_id)], message)
@@ -547,9 +548,7 @@
         stage_info, code = self.superseded_request(request, target_requests)
         if stage_info and (code is None or code == 'unstage'):
             # Remove the old request
-            self.rm_from_prj(stage_info['prj'],
-                             request_id=stage_info['rq_id'],
-                             msg='Replaced by sr#{}'.format(request_id))
+            self.rm_from_prj(stage_info['prj'], request_id=stage_info['rq_id'])
             if code is None:
                 # Add the new request that should be replacing the old one.
                 self.rq_to_prj(request_id, stage_info['prj'])
@@ -662,13 +661,11 @@
                 return x.get('package')
         return None
 
-    def rm_from_prj(self, project, package=None, request_id=None,
-                    msg=None):
+    def rm_from_prj(self, project, package=None, request_id=None):
         """
         Delete request from the project
         :param project: project to remove from
         :param request_id: request we want to remove
-        :param msg: message for the log
         :param review: review state for the review, defautl accepted
         """
 
@@ -969,6 +966,15 @@
             result.append({'project': package.get('project'), 'package': 
package.get('name')})
         return result
 
+    def _wipe_package(self, project, package):
+        url = self.makeurl(['build', project],
+                           {'cmd': 'wipe', 'package': package})
+        try:
+            http_POST(url)
+        except HTTPError as e:
+            print(e.read())
+            raise e
+
     def create_and_wipe_package(self, project, package):
         """
         Helper function for delete requests
@@ -977,9 +983,13 @@
         self.create_package_container(project, package, disable_build=True)
 
         # now trigger wipebinaries to emulate a delete
-        url = self.makeurl(['build', project],
-                           {'cmd': 'wipe', 'package': package})
-        http_POST(url)
+        self._wipe_package(project, package)
+
+        url = self.makeurl(['source', project, package], { 'view': 
'getmultibuild' })
+        f = http_GET(url)
+        root = ET.parse(f).getroot()
+        for entry in root.findall('entry'):
+            self._wipe_package(project, package + ":" + entry.get('name'))
 
     def delete_to_prj(self, act, project):
         """
@@ -1121,30 +1131,6 @@
         url = self.makeurl(['request', str(request_id)], query)
         http_POST(url, data=msg)
 
-    def set_review(self, request_id, project, state='accepted', msg=None):
-        """
-        Sets review for request done by project
-        :param request_id: request to change review for
-        :param project: project to do the review
-        """
-        req = get_request(self.apiurl, str(request_id))
-        if not req:
-            raise oscerr.WrongArgs('Request {} not found'.format(request_id))
-        # don't try to change reviews if the request is dead
-        if req.state.name not in ('new', 'review'):
-            return
-        cont = False
-        for i in req.reviews:
-            if i.by_project == project and i.state == 'new':
-                cont = True
-        if not cont:
-            return
-        if not msg:
-            msg = 'Reviewed by staging project "{}" with result: "{}"'
-            msg = msg.format(project, state)
-        self.do_change_review_state(request_id, state, by_project=project,
-                                    message=msg)
-
     def get_flag_in_prj(self, project, flag='build', repository=None, 
arch=None):
         """Return the flag value in a project."""
         url = self.makeurl(['source', project, '_meta'])
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/openSUSE-release-tools-20200306.ef1064e7/osclib/supersede_command.py 
new/openSUSE-release-tools-20200325.77a14833/osclib/supersede_command.py
--- old/openSUSE-release-tools-20200306.ef1064e7/osclib/supersede_command.py    
2020-03-06 13:26:18.000000000 +0100
+++ new/openSUSE-release-tools-20200325.77a14833/osclib/supersede_command.py    
2020-03-25 17:26:22.000000000 +0100
@@ -26,4 +26,4 @@
                 Fore.CYAN + target_package + Fore.RESET,
                 verbage,
                 stage_info['rq_id'],
-                Fore.YELLOW + stage_info['prj']))
+                Fore.YELLOW + stage_info['prj'] + Fore.RESET))
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/openSUSE-release-tools-20200306.ef1064e7/osclib/unselect_command.py 
new/openSUSE-release-tools-20200325.77a14833/osclib/unselect_command.py
--- old/openSUSE-release-tools-20200306.ef1064e7/osclib/unselect_command.py     
2020-03-06 13:26:18.000000000 +0100
+++ new/openSUSE-release-tools-20200325.77a14833/osclib/unselect_command.py     
2020-03-25 17:26:22.000000000 +0100
@@ -53,7 +53,7 @@
             staging_project = request_project['staging']
             affected_projects.add(staging_project)
             print('Unselecting "{}" from "{}"'.format(request, 
staging_project))
-            self.api.rm_from_prj(staging_project, request_id=request, 
msg='Removing from {}, re-evaluation needed'.format(staging_project))
+            self.api.rm_from_prj(staging_project, request_id=request)
 
             req = get_request(self.api.apiurl, str(request))
             if message:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/openSUSE-release-tools-20200306.ef1064e7/pkglistgen/group.py 
new/openSUSE-release-tools-20200325.77a14833/pkglistgen/group.py
--- old/openSUSE-release-tools-20200306.ef1064e7/pkglistgen/group.py    
2020-03-06 13:26:18.000000000 +0100
+++ new/openSUSE-release-tools-20200325.77a14833/pkglistgen/group.py    
2020-03-25 17:26:22.000000000 +0100
@@ -29,6 +29,7 @@
         self.srcpkgs = None
         self.develpkgs = dict()
         self.silents = set()
+        self.required = set()
         self.ignored = set()
         # special feature for SLE. Patterns are marked for expansion
         # of recommended packages, all others aren't. Only works
@@ -70,6 +71,8 @@
                     continue
                 elif rel == 'silent':
                     self.silents.add(name)
+                elif rel == 'required':
+                    self.required.add(name)
                 elif rel == 'recommended':
                     self.expand_recommended.add(name)
                 elif rel == 'suggested':
@@ -90,6 +93,7 @@
 
         self.locked.update(group.locked)
         self.silents.update(group.silents)
+        self.required.update(group.required)
         self.expand_recommended.update(group.expand_recommended)
         self.expand_suggested.update(group.expand_suggested)
 
@@ -168,10 +172,7 @@
                 if problems:
                     for problem in problems:
                         msg = 'unresolvable: {}:{}.{}: {}'.format(self.name, 
n, arch, problem)
-                        if self.pkglist.ignore_broken:
-                            self.logger.debug(msg)
-                        else:
-                            self.logger.debug(msg)
+                        self.logger.debug(msg)
                         self.unresolvable[arch][n] = str(problem)
                     return
 
@@ -334,14 +335,14 @@
                 continue
             if name in missing:
                 msg = ' {} not found on {}'.format(name, 
','.join(sorted(missing[name])))
-                if ignore_broken:
+                if ignore_broken and name not in self.required:
                     c = ET.Comment(msg)
                     packagelist.append(c)
                     continue
                 name = msg
             if name in unresolvable:
                 msg = ' {} uninstallable: {}'.format(name, unresolvable[name])
-                if ignore_broken:
+                if ignore_broken and name not in self.required:
                     c = ET.Comment(msg)
                     packagelist.append(c)
                     continue
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/openSUSE-release-tools-20200306.ef1064e7/pkglistgen/update_repo_handler.py 
new/openSUSE-release-tools-20200325.77a14833/pkglistgen/update_repo_handler.py
--- 
old/openSUSE-release-tools-20200306.ef1064e7/pkglistgen/update_repo_handler.py  
    2020-03-06 13:26:18.000000000 +0100
+++ 
new/openSUSE-release-tools-20200325.77a14833/pkglistgen/update_repo_handler.py  
    2020-03-25 17:26:22.000000000 +0100
@@ -17,6 +17,7 @@
 
 from osc import conf
 import osc.core
+from urllib.error import HTTPError
 from osclib.cache_manager import CacheManager
 
 import requests
@@ -128,7 +129,11 @@
         f.write(content.read())
         f.flush()
         os.lseek(f.fileno(), 0, os.SEEK_SET)
-        repo.add_susetags(f, defvendorid, None, solv.Repo.REPO_NO_INTERNALIZE 
| solv.Repo.SUSETAGS_RECORD_SHARES)
+        try:
+            repo.add_susetags(f, defvendorid, None, 
solv.Repo.REPO_NO_INTERNALIZE | solv.Repo.SUSETAGS_RECORD_SHARES)
+        except TypeError:
+            logger.error(f"Failed to add susetags for {url}")
+            return False
         return True
     return False
 
@@ -230,6 +235,10 @@
         os.unlink(solv_file)
 
         url = osc.core.makeurl(apiurl, ['source', project, '000update-repos', 
path + '.xz'])
-        osc.core.http_PUT(url, data=open(packages_file + '.xz', 'rb').read())
+        try:
+            osc.core.http_PUT(url, data=open(packages_file + '.xz', 
'rb').read())
+        except HTTPError:
+            logger.error(f"Failed to upload to {url}")
+            sys.exit(1)
 
         del pool
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/openSUSE-release-tools-20200306.ef1064e7/pkglistgen.md 
new/openSUSE-release-tools-20200325.77a14833/pkglistgen.md
--- old/openSUSE-release-tools-20200306.ef1064e7/pkglistgen.md  2020-03-06 
13:26:18.000000000 +0100
+++ new/openSUSE-release-tools-20200325.77a14833/pkglistgen.md  2020-03-25 
17:26:22.000000000 +0100
@@ -1,90 +1,92 @@
-# Package List Generator
-
-pkglistgen.py is a self contained script to generate and update OBS products 
for openSUSE and SLE. 
-It works on the products and its staging projects and ports.
-
-The main input is a package named 000package-groups and it will update the 
content of other packages
-from that. For that it will read [YAML](https://en.wikipedia.org/wiki/YAML) 
input from e.g. 000package-groups/groups.yml and generate .group files into 
000product. The rest of 000package-groups is copied into 000product as well and 
it runs the OBS product converter service (See [OBS 
Documentation](https://en.opensuse.org/openSUSE:Build_Service_product_definition)
 for details)
-The generated release spec files are split into 000release-packages to avoid 
needless rebuilds. 
-
-## Input
-
-The package list generator reads several files. The most important is 
groups.yml within 000package-groups
-
-### supportstatus.txt
- TODO
- 
-### groups.yml
-The file is a list of package lists and the special hash 'OUTPUT'. OUTPUT 
contains an entry for every group file that needs to be written out. The group 
name of it needs to exist as package list as well. OUTPUT also contains flags 
for the groups.
-
-We currently support:
- * default-support
- Sets the support level in case there is no explicitly entry in 
[supportstatus.txt](#supportstatus.txt), defaults to 'unsupported'
- * recommends
- If the solver should take recommends into account when solving the package 
list, defaults to false.
- * includes
- Adds package lists to the group to be solved. Allows to organize different 
topics into the same group. By default there are no package lists added - the 
package list with the group name is always there.
- * excludes
- Removes all packages from the __solved__ groups listed. Used to build addons 
to main products.
- * conflicts
- Sets package groups not to be part of the same product. Influences the 
[overlap calculation](#overlap-calculation) only.
-
-Be aware that group names must not contain a '-'.
-
-You can also adapt the solving on a package level by putting a hash into the 
package list. Normally the package name is a string, in case it's a hash the 
key needs to be the package name and the value is a list of following 
modifiers: 
-
- * recommended
- Evaluate also 'Recommends' in package to determine dependencies. Otherwise 
only 'required' are considered. Used mainly for patterns in SLE. It can not be 
combined with platforms, For architecture specific recommends, use patterns.
- * suggested
- Evaluate also 'Suggests' in package to determine dependencies. This implies 
recommended
- * architecture (e.g. x86_64,s390x,ppc64le,aarch64)
- Makes the entry specific to the listed architectures. Will get ignored if 
used in combination with 'recommended'.
- * locked
- Do not put the package into this group. Used to *force* certain packages into 
other modules
- * silent
- Use this package for dependency solving of groups "on top", but do not output 
the package for this group. Mainly to mark the product to use by adding release 
packages. Use with care, this breaks dependency chains!
-
-Note that you can write yaml lists in 2 ways. You can put the modifier lists 
as multiple lines starting with -, but it's recommended to put them as [M1,M2] 
behind the package name. See the difference between pkg4 and pkg5 in the 
example. 
-
-#### Example:
-
-```
-OUTPUT:
-  - group1:
-    includes:
-    - list1
-    - list2
-  - group2:
-    default-support: l3
-    recommends: true
-    includes:
-    - list3
-    excludes:
-    - group1
-    conflicts:
-    - group3
-  - group3:
-    includes:
-    - list2
-    
-group1:
-  - pkg1
-  
-group2:
-  - pkg2: [locked]
-  - pkg3
-  
-group3:
-  - pkg4: [x86_64]
-  
-list1:
-  - pkg5:
-    - x86_64
-  
-list2:
-  - pkg6: [recommended]
-``` 
-
-## Overlap calculcation
- TODO 
-
+# Package List Generator
+
+pkglistgen.py is a self contained script to generate and update OBS products 
for openSUSE and SLE. 
+It works on the products and its staging projects and ports.
+
+The main input is a package named 000package-groups and it will update the 
content of other packages
+from that. For that it will read [YAML](https://en.wikipedia.org/wiki/YAML) 
input from e.g. 000package-groups/groups.yml and generate .group files into 
000product. The rest of 000package-groups is copied into 000product as well and 
it runs the OBS product converter service (See [OBS 
Documentation](https://en.opensuse.org/openSUSE:Build_Service_product_definition)
 for details)
+The generated release spec files are split into 000release-packages to avoid 
needless rebuilds. 
+
+## Input
+
+The package list generator reads several files. The most important is 
groups.yml within 000package-groups
+
+### supportstatus.txt
+ TODO
+ 
+### groups.yml
+The file is a list of package lists and the special hash 'OUTPUT'. OUTPUT 
contains an entry for every group file that needs to be written out. The group 
name of it needs to exist as package list as well. OUTPUT also contains flags 
for the groups.
+
+We currently support:
+ * default-support
+ Sets the support level in case there is no explicitly entry in 
[supportstatus.txt](#supportstatus.txt), defaults to 'unsupported'
+ * recommends
+ If the solver should take recommends into account when solving the package 
list, defaults to false.
+ * includes
+ Adds package lists to the group to be solved. Allows to organize different 
topics into the same group. By default there are no package lists added - the 
package list with the group name is always there.
+ * excludes
+ Removes all packages from the __solved__ groups listed. Used to build addons 
to main products.
+ * conflicts
+ Sets package groups not to be part of the same product. Influences the 
[overlap calculation](#overlap-calculation) only.
+
+Be aware that group names must not contain a '-'.
+
+You can also adapt the solving on a package level by putting a hash into the 
package list. Normally the package name is a string, in case it's a hash the 
key needs to be the package name and the value is a list of following 
modifiers: 
+
+ * recommended
+ Evaluate also 'Recommends' in package to determine dependencies. Otherwise 
only 'required' are considered. Used mainly for patterns in SLE. It can not be 
combined with platforms, For architecture specific recommends, use patterns.
+ * suggested
+ Evaluate also 'Suggests' in package to determine dependencies. This implies 
recommended
+ * architecture (e.g. x86_64,s390x,ppc64le,aarch64)
+ Makes the entry specific to the listed architectures. Will get ignored if 
used in combination with 'recommended'.
+ * locked
+ Do not put the package into this group. Used to *force* certain packages into 
other modules
+ * silent
+ Use this package for dependency solving of groups "on top", but do not output 
the package for this group. Mainly to mark the product to use by adding release 
packages. Use with care, this breaks dependency chains!
+ * required
+ If the package is missing or is uninstallable, don't leave a comment but put 
the error as package entry for OBS to create unresolvable error to avoid 
building a DVD
+
+Note that you can write yaml lists in 2 ways. You can put the modifier lists 
as multiple lines starting with -, but it's recommended to put them as [M1,M2] 
behind the package name. See the difference between pkg4 and pkg5 in the 
example. 
+
+#### Example:
+
+```
+OUTPUT:
+  - group1:
+    includes:
+    - list1
+    - list2
+  - group2:
+    default-support: l3
+    recommends: true
+    includes:
+    - list3
+    excludes:
+    - group1
+    conflicts:
+    - group3
+  - group3:
+    includes:
+    - list2
+    
+group1:
+  - pkg1
+  
+group2:
+  - pkg2: [locked]
+  - pkg3
+  
+group3:
+  - pkg4: [x86_64]
+  
+list1:
+  - pkg5:
+    - x86_64
+  
+list2:
+  - pkg6: [recommended]
+``` 
+
+## Overlap calculcation
+ TODO 
+
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/openSUSE-release-tools-20200306.ef1064e7/staging-installcheck.py 
new/openSUSE-release-tools-20200325.77a14833/staging-installcheck.py
--- old/openSUSE-release-tools-20200306.ef1064e7/staging-installcheck.py        
2020-03-06 13:26:18.000000000 +0100
+++ new/openSUSE-release-tools-20200325.77a14833/staging-installcheck.py        
2020-03-25 17:26:22.000000000 +0100
@@ -15,6 +15,7 @@
 
 from osclib.comments import CommentAPI
 from osclib.conf import Config
+from osclib.conf import str2bool
 from osclib.core import (builddepinfo, depends_on, duplicated_binaries_in_repo,
                          fileinfo_ext_all, repository_arch_state,
                          repository_path_expand, target_archs)
@@ -42,6 +43,7 @@
 
         self.ignore_duplicated = 
set(self.config.get('installcheck-ignore-duplicated-binaries', '').split(' '))
         self.ignore_conflicts = 
set(self.config.get('installcheck-ignore-conflicts', '').split(' '))
+        self.ignore_deletes = 
str2bool(self.config.get('installcheck-ignore-deletes', 'False'))
 
     def check_required_by(self, fileinfo, provides, requiredby, 
built_binaries, comments):
         if requiredby.get('name') in built_binaries:
@@ -69,7 +71,7 @@
 
     def check_delete_request(self, req, to_ignore, comments):
         package = req.get('package')
-        if package in to_ignore:
+        if package in to_ignore or self.ignore_deletes:
             self.logger.info('Delete request for package {} 
ignored'.format(package))
             return True
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/openSUSE-release-tools-20200306.ef1064e7/tests/OBSLocal.py 
new/openSUSE-release-tools-20200325.77a14833/tests/OBSLocal.py
--- old/openSUSE-release-tools-20200306.ef1064e7/tests/OBSLocal.py      
2020-03-06 13:26:18.000000000 +0100
+++ new/openSUSE-release-tools-20200325.77a14833/tests/OBSLocal.py      
2020-03-25 17:26:22.000000000 +0100
@@ -24,6 +24,7 @@
 from osclib.stagingapi import StagingAPI
 from osclib.core import attribute_value_save
 from osclib.core import request_state_change
+from osclib.core import create_delete_request
 from osclib.memoize import memoize_session_reset
 
 from urllib.error import HTTPError, URLError
@@ -66,6 +67,8 @@
             f.write('\n'.join([
                 '[general]',
                 'apiurl = http://api:3000',
+                'http_debug = false',
+                'debug = false',
                 'cookiejar = {}'.format(OSCCOOKIEJAR),
                 '[http://api:3000]',
                 'user = {}'.format(userid),
@@ -227,6 +230,7 @@
 
         config = {
             'overridden-by-local': 'remote-nope',
+            'staging-group': 'factory-staging',
             'remote-only': 'remote-indeed',
         }
         self.remote_config_set(config, replace_all=True)
@@ -282,8 +286,12 @@
 
     def create_target(self):
         if self.projects.get('target'): return
-        self.create_group('factory-staging')
-        self.projects['target'] = Project(name=self.project, 
reviewer={'groups': ['factory-staging']})
+        self.create_user('staging-bot')
+        self.create_group('factory-staging', users=['staging-bot'])
+        p = Project(name=self.project, reviewer={'groups': 
['factory-staging']})
+        self.projects['target'] = p
+        self.projects[self.project] = p
+
         url = osc.core.makeurl(APIURL, ['staging', self.project, 'workflow'])
         data = "<workflow managers='factory-staging'/>"
         osc.core.http_POST(url, data=data)
@@ -329,18 +337,25 @@
         self.requests.append(request)
         return request
 
+    def request_package_delete(self, package, project=None):
+        if not project:
+            project = package.project
+        request = Request(target_package=package, target_project=project, 
type='delete')
+        self.requests.append(request)
+        return request
+
     def create_submit_request(self, project, package, text=None):
         project = self.create_project(project)
         package = Package(name=package, project=project)
         package.create_commit(text=text)
         return self.submit_package(package)
 
-    def create_staging(self, suffix, freeze=False, rings=None):
+    def create_staging(self, suffix, freeze=False, rings=None, 
with_repo=False):
         staging_key = 'staging:{}'.format(suffix)
         # do not reattach if already present
         if not staging_key in self.projects:
             staging_name = self.project + ':Staging:' + suffix
-            staging = Project(staging_name, create=False)
+            staging = Project(staging_name, create=False, with_repo=with_repo)
             url = osc.core.makeurl(APIURL, ['staging', self.project, 
'staging_projects'])
             data = '<workflow><staging_project>{}</staging_project></workflow>'
             osc.core.http_POST(url, data=data.format(staging_name))
@@ -353,7 +368,8 @@
             project_links.append(self.project + ":Rings:0-Bootstrap")
         if rings == 1 or rings == 0:
             project_links.append(self.project + ":Rings:1-MinimalX")
-        staging.update_meta(project_links=project_links)
+        staging.update_meta(project_links=project_links, maintainer={'groups': 
['factory-staging']},
+                            with_repo=with_repo)
 
         if freeze:
             FreezeCommand(self.api).perform(staging.name)
@@ -388,16 +404,16 @@
             self.api._invalidate_all()
 
 class Project(object):
-    def __init__(self, name, reviewer={}, maintainer={}, project_links=[], 
create=True):
+    def __init__(self, name, reviewer={}, maintainer={}, project_links=[], 
create=True, with_repo=False):
         self.name = name
         self.packages = []
 
         if not create:
             return
 
-        self.update_meta(reviewer, maintainer, project_links)
+        self.update_meta(reviewer, maintainer, project_links, 
with_repo=with_repo)
 
-    def update_meta(self, reviewer={}, maintainer={}, project_links=[]):
+    def update_meta(self, reviewer={}, maintainer={}, project_links=[], 
with_repo=False):
         meta = """
             <project name="{0}">
               <title></title>
@@ -417,6 +433,11 @@
 
         for link in project_links:
             ET.SubElement(root, 'link', { 'project': link })
+
+        if with_repo:
+            repo = ET.SubElement(root, 'repository', { 'name': 'standard' })
+            ET.SubElement(repo, 'arch').text = 'x86_64'
+
         self.custom_meta(ET.tostring(root))
 
     def add_package(self, package):
@@ -492,18 +513,23 @@
         osc.core.http_PUT(url, data=text)
 
 class Request(object):
-    def __init__(self, source_package, target_project):
-        self.source_package = source_package
-        self.target_project = target_project
-
-        self.reqid = osc.core.create_submit_request(APIURL,
-                                 src_project=self.source_package.project.name,
-                                 src_package=self.source_package.name,
-                                 dst_project=self.target_project)
-        self.revoked = False
+    def __init__(self, source_package=None, target_project=None, 
target_package=None, type='submit'):
+        self.revoked = True
 
-        print('created submit request {}/{} -> {}'.format(
-            self.source_package.project.name, self.source_package.name, 
self.target_project))
+        if type == 'submit':
+            self.reqid = osc.core.create_submit_request(APIURL,
+                                     src_project=source_package.project.name,
+                                     src_package=source_package.name,
+                                     dst_project=target_project,
+                                     dst_package=target_package)
+            print('created submit request {}/{} -> {}'.format(
+                source_package.project.name, source_package.name, 
target_project))
+        elif type == 'delete':
+            self.reqid = create_delete_request(APIURL, target_project.name, 
target_package.name)
+        else:
+            raise oscerr.WrongArgs(f'unknown request type {type}')
+
+        self.revoked = False
 
     def __del__(self):
         self.revoke()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/openSUSE-release-tools-20200306.ef1064e7/tests/api_tests.py 
new/openSUSE-release-tools-20200325.77a14833/tests/api_tests.py
--- old/openSUSE-release-tools-20200306.ef1064e7/tests/api_tests.py     
2020-03-06 13:26:18.000000000 +0100
+++ new/openSUSE-release-tools-20200325.77a14833/tests/api_tests.py     
2020-03-25 17:26:22.000000000 +0100
@@ -168,20 +168,6 @@
         self.wf.api.add_review(num, by_project='openSUSE:Factory:Staging:B')
         self.assertEqual(request.reviews(), reviews)
 
-        # Accept review
-        self.wf.api.set_review(num, 'openSUSE:Factory:Staging:B')
-        reviews[1]['state'] = 'accepted'
-        self.assertEqual(request.reviews(), reviews)
-
-        # Try to accept it again should do anything
-        self.wf.api.set_review(num, 'openSUSE:Factory:Staging:B')
-        self.assertEqual(request.reviews(), reviews)
-
-        # But we should be able to reopen it
-        self.wf.api.add_review(num, by_project='openSUSE:Factory:Staging:B')
-        reviews.append({'by_project': 'openSUSE:Factory:Staging:B', 'state': 
'new'})
-        self.assertEqual(request.reviews(), reviews)
-
     def test_prj_from_letter(self):
 
         # Verify it works
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/openSUSE-release-tools-20200306.ef1064e7/tests/fixtures/staging-meta-for-bootstrap-copy.xml
 
new/openSUSE-release-tools-20200325.77a14833/tests/fixtures/staging-meta-for-bootstrap-copy.xml
--- 
old/openSUSE-release-tools-20200306.ef1064e7/tests/fixtures/staging-meta-for-bootstrap-copy.xml
     2020-03-06 13:26:18.000000000 +0100
+++ 
new/openSUSE-release-tools-20200325.77a14833/tests/fixtures/staging-meta-for-bootstrap-copy.xml
     2020-03-25 17:26:22.000000000 +0100
@@ -18,12 +18,12 @@
        <arch>i586</arch>
        <arch>x86_64</arch>
   </repository>
-  <repository linkedbuild="all" name="standard" rebuild="direct">
+  <repository name="standard" linkedbuild="all" rebuild="direct">
     <path project="openSUSE:Factory:Staging:A" repository="bootstrap_copy"/>
     <arch>i586</arch>
     <arch>x86_64</arch>
   </repository>
-  <repository linkedbuild="all" name="images">
+  <repository name="images" linkedbuild="all">
     <path project="openSUSE:Factory:Staging:A" repository="standard"/>
     <arch>x86_64</arch>
   </repository>
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/openSUSE-release-tools-20200306.ef1064e7/tests/origin_tests.py 
new/openSUSE-release-tools-20200325.77a14833/tests/origin_tests.py
--- old/openSUSE-release-tools-20200306.ef1064e7/tests/origin_tests.py  
2020-03-06 13:26:18.000000000 +0100
+++ new/openSUSE-release-tools-20200325.77a14833/tests/origin_tests.py  
2020-03-25 17:26:22.000000000 +0100
@@ -41,7 +41,8 @@
         self.review_group = self.randomString('group')
         self.wf.create_group(self.review_group, [self.review_user])
 
-        self.wf.create_project(self.target_project, reviewer={'users': 
[self.bot_user]})
+        target = self.wf.create_project(self.target_project)
+        target.update_meta(reviewer={'users': [self.bot_user]})
 
     def tearDown(self):
         super().tearDown()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/openSUSE-release-tools-20200306.ef1064e7/tests/select_tests.py 
new/openSUSE-release-tools-20200325.77a14833/tests/select_tests.py
--- old/openSUSE-release-tools-20200306.ef1064e7/tests/select_tests.py  
2020-03-06 13:26:18.000000000 +0100
+++ new/openSUSE-release-tools-20200325.77a14833/tests/select_tests.py  
2020-03-25 17:26:22.000000000 +0100
@@ -2,6 +2,8 @@
 import os.path
 from osc import oscerr
 import osc.conf
+from osc.core import http_GET, http_POST, makeurl
+from lxml import etree as ET
 from osclib.cache import Cache
 from osclib.cache_manager import CacheManager
 from osclib.comments import CommentAPI
@@ -9,6 +11,7 @@
 from osclib.core import package_list
 from osclib.select_command import SelectCommand
 from osclib.unselect_command import UnselectCommand
+from osclib.supersede_command import SupersedeCommand
 from osclib.stagingapi import StagingAPI
 from osclib.memoize import memoize_session_reset
 from osclib.core import source_file_load
@@ -17,15 +20,16 @@
 from mock import MagicMock
 from . import OBSLocal
 
-class TestSelect(unittest.TestCase):
+class TestSelect(OBSLocal.TestCase):
 
     def setUp(self):
+        super().setUp()
         super(TestSelect, self).setUp()
         self.wf = OBSLocal.StagingWorkflow()
 
     def tearDown(self):
-        del self.wf
         super(TestSelect, self).tearDown()
+        del self.wf
 
     def test_old_frozen(self):
         self.wf.api.prj_frozen_enough = MagicMock(return_value=False)
@@ -99,3 +103,36 @@
 
         # no stale links
         self.assertEqual([], package_list(self.wf.apiurl, staging.name))
+
+    def test_supersede(self):
+        self.wf.setup_rings()
+        staging = self.wf.create_staging('A', freeze=True)
+
+        rq1 = self.wf.create_submit_request('devel:wine', 'wine')
+        ret = SelectCommand(self.wf.api, staging.name).perform(['wine'])
+        rq2 = self.wf.create_submit_request('devel:wine', 'wine', 
text='Something new')
+        self.wf.api._packages_staged = None
+
+        self.osc_user('staging-bot')
+        Config.get(self.wf.apiurl, self.wf.project)
+
+        SupersedeCommand(self.wf.api).perform()
+
+        self.assertEqual(rq1.reviews(), [{'state': 'accepted', 'by_group': 
'factory-staging'}, {'state': 'accepted', 'by_project': 
'openSUSE:Factory:Staging:A'},
+                                    {'state': 'declined', 'by_group': 
'factory-staging'}])
+        self.assertEqual(rq2.reviews(), [{'state': 'accepted', 'by_group': 
'factory-staging'}, {'state': 'new', 'by_project': 
'openSUSE:Factory:Staging:A'}])
+
+    def test_delete_multibuild_package(self):
+        self.wf.setup_rings()
+        staging = self.wf.create_staging('A', freeze=True, with_repo=True)
+
+        package = self.wf.create_package(self.wf.project, 'wine')
+        
package.create_commit('<multibuild><flavor>libs</flavor></multibuild>', 
filename='_multibuild')
+
+        rq = self.wf.request_package_delete(package)
+        ret = SelectCommand(self.wf.api, staging.name).perform(['wine'])
+        self.assertEqual(True, ret)
+
+        # TODO: record which URLs were called so we can verify them
+        # but we wont' be able to test the actual wipe unless we really build 
something
+        # which is too expensive

++++++ openSUSE-release-tools.obsinfo ++++++
--- /var/tmp/diff_new_pack.RwcbiT/_old  2020-04-03 15:52:50.089834717 +0200
+++ /var/tmp/diff_new_pack.RwcbiT/_new  2020-04-03 15:52:50.089834717 +0200
@@ -1,5 +1,5 @@
 name: openSUSE-release-tools
-version: 20200306.ef1064e7
-mtime: 1583497578
-commit: ef1064e73b8faa944b47bd746b23caff1476c128
+version: 20200325.77a14833
+mtime: 1585153582
+commit: 77a148335e9cda52262f642d8c9a27bc87b570e3
 


Reply via email to