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 2021-09-20 23:33:27
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/openSUSE-release-tools (Old)
 and      /work/SRC/openSUSE:Factory/.openSUSE-release-tools.new.1899 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "openSUSE-release-tools"

Mon Sep 20 23:33:27 2021 rev:328 rq:920284 version:20210920.e1eef928

Changes:
--------
--- 
/work/SRC/openSUSE:Factory/openSUSE-release-tools/openSUSE-release-tools.changes
    2021-09-17 23:26:19.833256458 +0200
+++ 
/work/SRC/openSUSE:Factory/.openSUSE-release-tools.new.1899/openSUSE-release-tools.changes
  2021-09-20 23:36:17.895406704 +0200
@@ -1,0 +2,7 @@
+Mon Sep 20 09:42:05 UTC 2021 - opensuse-releaset...@opensuse.org
+
+- Update to version 20210920.e1eef928:
+  * Link the new testcase from processes.md
+  * Test to showcase a submit request to SLE
+
+-------------------------------------------------------------------

Old:
----
  openSUSE-release-tools-20210916.1cb39a18.obscpio

New:
----
  openSUSE-release-tools-20210920.e1eef928.obscpio

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

Other differences:
------------------
++++++ openSUSE-release-tools.spec ++++++
--- /var/tmp/diff_new_pack.vMmuXW/_old  2021-09-20 23:36:18.507407460 +0200
+++ /var/tmp/diff_new_pack.vMmuXW/_new  2021-09-20 23:36:18.511407465 +0200
@@ -20,7 +20,7 @@
 %define source_dir openSUSE-release-tools
 %define announcer_filename factory-package-news
 Name:           openSUSE-release-tools
-Version:        20210916.1cb39a18
+Version:        20210920.e1eef928
 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.vMmuXW/_old  2021-09-20 23:36:18.547407509 +0200
+++ /var/tmp/diff_new_pack.vMmuXW/_new  2021-09-20 23:36:18.547407509 +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">1cb39a18350f6ade62c4f02e8914c6f0f1b72c56</param>
+    <param 
name="changesrevision">e1eef928bd70a6c7d84a4c49060c89b10653bff0</param>
   </service>
 </servicedata>

++++++ openSUSE-release-tools-20210916.1cb39a18.obscpio -> 
openSUSE-release-tools-20210920.e1eef928.obscpio ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/openSUSE-release-tools-20210916.1cb39a18/docs/processes.md 
new/openSUSE-release-tools-20210920.e1eef928/docs/processes.md
--- old/openSUSE-release-tools-20210916.1cb39a18/docs/processes.md      
2021-09-16 16:29:36.000000000 +0200
+++ new/openSUSE-release-tools-20210920.e1eef928/docs/processes.md      
2021-09-20 11:40:45.000000000 +0200
@@ -38,7 +38,7 @@
 
workflows](https://github.com/openSUSE/open-build-service/wiki/Staging-Workflow),
 extending and
 adapting them to the (open)SUSE use case.
 
-This [testcase](../tests/factory_submit_request_test.py) showcases the whole 
submission process
+This [testcase](../tests/factory_submit_request_tests.py) showcases the whole 
submission process
 explaining how the different reviews are created and processed by OBS and by 
the involved bots and
 release tools.
 
@@ -114,7 +114,9 @@
 like the [Origin Manager](./origin-manager.md) to verify aspects that are not 
relevant for
 Tumbleweed.
 
-The following [SUSE-internal
+This [testcase](../tests/sle_submit_request_tests.py) showcases the whole 
submission process
+explaining how the different reviews are created and processed by IBS and by 
the involved bots and
+release tools. Additionally, the following [SUSE-internal
 
document](https://confluence.suse.com/display/projectmanagement/Product+Handbook)
 offers all kind of
 details about the processes involved in the development of SLE and all its 
associated products.
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/openSUSE-release-tools-20210916.1cb39a18/tests/OBSLocal.py 
new/openSUSE-release-tools-20210920.e1eef928/tests/OBSLocal.py
--- old/openSUSE-release-tools-20210916.1cb39a18/tests/OBSLocal.py      
2021-09-16 16:29:36.000000000 +0200
+++ new/openSUSE-release-tools-20210920.e1eef928/tests/OBSLocal.py      
2021-09-20 11:40:45.000000000 +0200
@@ -30,6 +30,7 @@
 from urllib.error import HTTPError, URLError
 
 from abc import ABC, abstractmethod
+import re
 
 # pointing to other docker container
 APIURL = 'http://api:3000'
@@ -257,6 +258,21 @@
         """Used to ensure different test runs operate in unique namespace."""
         return '::'.join([type(self).__name__, user, 
str(random.getrandbits(8))])
 
+    def assertReviewBot(self, request_id, user, before, after, comment=None):
+        """Asserts the review bot associated to the given user produces the 
expected change in the
+        reviews of a request.
+
+        This is very similar to :func:`assertReviewScript`, but it executes 
the corresponding review
+        bot instead of the script pointed by the ``script`` attribute.
+        """
+        self.assertReview(request_id, by_user=(user, before))
+
+        self.execute_review_bot([request_id], user)
+
+        review = self.assertReview(request_id, by_user=(user, after))
+        if comment:
+            self.assertEqual(review.comment, comment)
+
 class StagingWorkflow(ABC):
     """This abstract base class is intended to setup and manipulate the 
environment (projects,
     users, etc.) in the local OBS instance used to tests the release tools. 
Thus, the derivative
@@ -694,6 +710,71 @@
 
         return staging
 
+class SLEWorkflow(StagingWorkflow):
+    """A class that makes easy to setup scenarios similar to the one used 
during the real
+    SLE development, with projects that inherit some packages from previous 
service packs, etc.
+    """
+    def staging_group_name(self):
+        return 'sle-staging-managers'
+
+    def initial_config(self):
+        return {
+            'staging-group': self.staging_group_name()
+        }
+
+    def create_target_project(self):
+        """Creates the main target project (see :func:`create_target`)
+
+        If the name of the target project follows the SLE naming convention of 
using "SP" to
+        indicate a service pack and a prefix "GA" or "Update", this also 
creates all the linked
+        projects needed to implement package inheritance. For example, if the 
target name is
+        "SLE-15-SP1:Update", the method will create that project and also the 
projects
+        "SLE-15-SP1:GA", "SLE-15:Update", "SLE-15:GA", linking each project to 
the corresponding one
+        in the inheritance chain.
+        """
+        if not re.search(r'.+:(GA|Update)$', self.project):
+            super().create_target_project()
+            return
+
+        suffixes = ["GA", "Update"]
+        basename, number, suffix = self._prj_name_components(self.project)
+        last = number * 2 + suffixes.index(suffix)
+
+        previous = None
+        for num in range(0, last + 1):
+            name = self._sp_name(basename, int(num / 2))
+            suffix = suffixes[num % 2]
+            name = name + ":" + suffix
+
+            if previous:
+                p = Project(name, project_links=[previous])
+            else:
+                p = Project(name)
+
+            self.projects[name] = p
+            previous = name
+
+        self.projects['target'] = self.projects[self.project]
+
+    def _prj_name_components(self, prj_name):
+        """Internal function to break a SLE-like name into pieces"""
+        distro, suffix = prj_name.rsplit(":", 1)
+        match = re.search(r'(.*)-SP(\d+)$', distro)
+        if match:
+            number = int(match.group(2))
+            basename = match.group(1)
+        else:
+            number = 0
+            basename = distro
+        return [basename, number, suffix]
+
+    def _sp_name(self, basename, number):
+        """Internal function to build a SLE-like name"""
+        if number > 0:
+            return f'{basename}-SP{number}'
+        else:
+            return basename
+
 class Project(object):
     """This class represents a project in the testing environment of the 
release tools. It usually
     corresponds to a project in the local OBS instance that is used by the 
tests.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/openSUSE-release-tools-20210916.1cb39a18/tests/sle_submit_request_tests.py 
new/openSUSE-release-tools-20210920.e1eef928/tests/sle_submit_request_tests.py
--- 
old/openSUSE-release-tools-20210916.1cb39a18/tests/sle_submit_request_tests.py  
    1970-01-01 01:00:00.000000000 +0100
+++ 
new/openSUSE-release-tools-20210920.e1eef928/tests/sle_submit_request_tests.py  
    2021-09-20 11:40:45.000000000 +0200
@@ -0,0 +1,205 @@
+import logging
+from . import OBSLocal
+import random
+import os
+
+# Needed to configure OriginManager
+import yaml
+from osclib.core import attribute_value_save
+
+# Needed to mock LegalAuto
+from osc.core import change_review_state
+from mock import MagicMock
+
+# Import the involved staging commands
+from osclib.freeze_command import FreezeCommand
+from osclib.select_command import SelectCommand
+from osclib.accept_command import AcceptCommand
+
+# Import the involved bots
+from check_source import CheckSource
+from check_tags_in_requests import TagChecker
+legal_auto = __import__("legal-auto") # Needed because of the dash in the 
filename
+LegalAuto = legal_auto.LegalAuto
+origin_manager = __import__("origin-manager") # Same than above, dash in the 
filename
+OriginManager = origin_manager.OriginManager
+
+PROJECT = 'SUSE:SLE-15-SP3:GA'
+DEVEL_PROJECT = 'devel:drinking'
+STAGING_PROJECT_NAME = 'SUSE:SLE-15-SP3:GA:Staging:A'
+HUMAN_REVIEWER = 'release-manager'
+FIXTURES = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'fixtures')
+
+class TestSLESubmitRequest(OBSLocal.TestCase):
+    """Tests for the whole lifecycle of submit requests in SLE
+
+    Similar in purpose and philosophy to TestFactorySubmitRequest, check
+    factory_submit_request_tests.py for more details
+    """
+
+    def setUp(self):
+        super(TestSLESubmitRequest, self).setUp()
+
+        # Setup the basic scenario, with manual reviewers, staging 
projects[...]
+        self.wf = OBSLocal.SLEWorkflow(PROJECT)
+        self.__setup_review_teams()
+        self.__setup_devel_package('wine')
+        self.__config_origin_manager()
+
+        # Setup the different bots typically used for Factory
+        self.setup_review_bot(self.wf, PROJECT, 'factory-auto', CheckSource)
+        self.setup_review_bot(self.wf, PROJECT, 'licensedigger', LegalAuto)
+        self.setup_review_bot(self.wf, PROJECT, 'sle-changelog-checker', 
TagChecker)
+        self.setup_review_bot(self.wf, PROJECT, 'origin-manager', 
OriginManager)
+
+        # Simulating the environment to please some of the bots while keeping 
this test readable
+        # may be a bit more tricky than it seems. Check the descriptions of 
__mock_licendigger and
+        # __mock_changelog_checker for more rationale
+        self.__mock_licensedigger()
+        self.__mock_changelog_checker()
+
+        # The staging project must be frozen in order to move packages into it
+        FreezeCommand(self.wf.api).perform(STAGING_PROJECT_NAME)
+
+        # Create the submit request
+        self.request = self.wf.create_submit_request(DEVEL_PROJECT, 'wine')
+
+    def tearDown(self):
+        super().tearDown()
+        del self.wf
+
+    def project(self):
+        return self.wf.projects[PROJECT]
+
+    def test_happy_path(self):
+        """Tests the ideal case in which all bots are happy and the request 
successfully goes
+        through staging"""
+
+        reqid = self.request.reqid
+
+        # Initial state: reviews have been created for...
+        # ...three human reviewers...
+        self.assertReview(reqid, by_group=('sle-release-managers', 'new'))
+        self.assertReview(reqid, by_group=('autobuild-team', 'new'))
+        self.assertReview(reqid, by_group=('origin-reviewers', 'new'))
+        # ...for the staging workflow...
+        self.assertReview(reqid, by_group=('sle-staging-managers', 'new'))
+
+        # ...and for the bots.
+        # So let's first execute the bots and verify their results
+        self.assertReviewBot(reqid, 'factory-auto', 'new', 'accepted')
+        self.assertReviewBot(reqid, 'licensedigger', 'new', 'accepted')
+        self.assertReviewBot(reqid, 'origin-manager', 'new', 'accepted')
+        self.assertReviewBot(reqid, 'sle-changelog-checker', 'new', 'accepted')
+
+        # So now that bots are happy, let's accept the manual reviews
+        self.osc_user(HUMAN_REVIEWER)
+        change_review_state(self.wf.apiurl, reqid, 'accepted', 
by_group='sle-release-managers')
+        change_review_state(self.wf.apiurl, reqid, 'accepted', 
by_group='autobuild-team')
+        change_review_state(self.wf.apiurl, reqid, 'accepted', 
by_group='origin-reviewers')
+        self.osc_user_pop()
+
+        # Now only the staging workflow is pending
+        self.assertReview(reqid, by_group=('sle-release-managers', 'accepted'))
+        self.assertReview(reqid, by_group=('autobuild-team', 'accepted'))
+        self.assertReview(reqid, by_group=('origin-reviewers', 'accepted'))
+        self.assertReview(reqid, by_group=('sle-staging-managers', 'new'))
+
+        # Before using the staging plugin, we need to force a reload of the 
configuration
+        # because assertReviewBot temporarily switches the user and that 
causes problems
+        self.wf.load_config()
+
+        # One staging manager puts the request into the staging project
+        SelectCommand(self.wf.api, STAGING_PROJECT_NAME).perform(['wine'])
+
+        # The sle-staging-managers review is now accepted and a new review 
associated to
+        # the staging project has been created
+        self.assertReview(reqid, by_group=('sle-staging-managers', 'accepted'))
+        self.assertReview(reqid, by_project=(STAGING_PROJECT_NAME, 'new'))
+
+        # Let's say everything looks good in the staging project, so the 
staging manager can
+        # accept that staging
+        AcceptCommand(self.wf.api).accept_all([STAGING_PROJECT_NAME], True)
+
+        # Finally, all the reviews are accepted:
+        # ...one for each bot,
+        self.assertReview(reqid, by_user=('factory-auto', 'accepted'))
+        self.assertReview(reqid, by_user=('licensedigger', 'accepted'))
+        self.assertReview(reqid, by_user=('sle-changelog-checker', 'accepted'))
+        self.assertReview(reqid, by_user=('origin-manager', 'accepted'))
+        # ...one for each manual review
+        self.assertReview(reqid, by_group=('sle-release-managers', 'accepted'))
+        self.assertReview(reqid, by_group=('autobuild-team', 'accepted'))
+        self.assertReview(reqid, by_group=('origin-reviewers', 'accepted'))
+        # ...and two for the staging project (one as a consequence of 
selecting the package into a
+        # staging project and the other as a consequence of accepting the 
staging)
+        self.assertReview(reqid, by_group=('sle-staging-managers', 'accepted'))
+        self.assertReview(reqid, by_project=(STAGING_PROJECT_NAME, 'accepted'))
+
+        # So it's time to accept the request
+        self.request.change_state('accepted')
+        self.assertRequestState(reqid, name='accepted')
+
+    def __setup_devel_package(self, pkg_name):
+        pkg = self.wf.create_package(DEVEL_PROJECT, pkg_name)
+        pkg.commit_files(os.path.join(FIXTURES, 'packages', pkg_name))
+
+        target_pkg = OBSLocal.Package(pkg_name, project=self.project(), 
devel_project=DEVEL_PROJECT)
+        target_pkg.create_commit()
+
+    def __setup_review_teams(self):
+        """Creates the different review teams for manual reviews.
+
+        For simplicity, this uses a common user for all groups.
+
+        This also sets those groups as reviewers of the target project, to 
ensure new reviews are
+        created for them as soon as the request is created. Note the 
difference with the Factory
+        workflow, in which the groups of human reviewers are not initially set 
as reviewers in the
+        target project configuration. Instead, in Factory the review targeting 
the human reviewers
+        is created by the factory-auto (CheckSource) bot.
+        """
+        self.wf.create_user(HUMAN_REVIEWER)
+        groups = ['sle-release-managers', 'origin-reviewers', 'autobuild-team']
+        for group in groups:
+            self.wf.create_group(group, users=[HUMAN_REVIEWER])
+            self.project().add_reviewers(groups = [group])
+
+    def __config_origin_manager(self):
+        """Creates the very minimal configuration needed by origin-manager to 
work"""
+        self.wf.create_attribute_type('OSRT', 'OriginConfig', 1)
+        self.wf.remote_config_set({'originmanager-request-age-min': 0})
+        config = {
+            'origins': [{'<devel>': {}}],
+            'review-user': 'origin-manager',
+            'fallback-group': 'origin-reviewers'
+        }
+        config = yaml.dump(config, default_flow_style=False)
+        attribute_value_save(self.wf.apiurl, PROJECT, 'OriginConfig', config)
+
+    def __mock_changelog_checker(self):
+        """Mocks the verification done by the TagChecker.
+
+        Normally, the bot checks whether the request references an entry in 
any of the known
+        issue trackers or whether the same request has been sent to Factory. 
Although simulating one
+        of those scenarios looks easy (and probably is), the whole check is 
mocked to return True
+        for simplicity (the rest of the execution of the bot still takes place 
normally).
+        """
+        bot = self.review_bots['sle-changelog-checker']
+        bot.checkTagInRequest = MagicMock(return_value = True)
+
+    def __mock_licensedigger(self):
+        """Mocks the execution of the LegalAuto bot, so it always succeeds and 
accepts the review
+
+        Unfortunatelly, LegalAuto is not written to be testable and it's very 
dependant on external
+        components. So just mocking its whole execution looks like the 
simplest solution for the
+        time being. Hopefully this whole mock could be removed in the future.
+        """
+        bot = self.review_bots['licensedigger']
+        bot.check_requests = MagicMock(side_effect=self.__accept_license)
+
+    def __accept_license(self):
+        """See :func:`__mock_licensedigger`"""
+        change_review_state(
+            apiurl = self.wf.apiurl, reqid = self.request.reqid,
+            newstate = 'accepted', by_user='licensedigger'
+        )

++++++ openSUSE-release-tools.obsinfo ++++++
--- /var/tmp/diff_new_pack.vMmuXW/_old  2021-09-20 23:36:19.155408260 +0200
+++ /var/tmp/diff_new_pack.vMmuXW/_new  2021-09-20 23:36:19.155408260 +0200
@@ -1,5 +1,5 @@
 name: openSUSE-release-tools
-version: 20210916.1cb39a18
-mtime: 1631802576
-commit: 1cb39a18350f6ade62c4f02e8914c6f0f1b72c56
+version: 20210920.e1eef928
+mtime: 1632130845
+commit: e1eef928bd70a6c7d84a4c49060c89b10653bff0
 

Reply via email to