Ejemplo n.º 1
0
def populate(db):
    """
    Create some data for tests to use.

    Args:
        db (sqlalchemy.orm.session.Session): The database session.
    """
    user = User(name=u'guest')
    db.add(user)
    anonymous = User(name=u'anonymous')
    db.add(anonymous)
    provenpackager = Group(name=u'provenpackager')
    db.add(provenpackager)
    packager = Group(name=u'packager')
    db.add(packager)
    user.groups.append(packager)
    release = Release(name=u'F17',
                      long_name=u'Fedora 17',
                      id_prefix=u'FEDORA',
                      version=u'17',
                      dist_tag=u'f17',
                      stable_tag=u'f17-updates',
                      testing_tag=u'f17-updates-testing',
                      candidate_tag=u'f17-updates-candidate',
                      pending_signing_tag=u'f17-updates-testing-signing',
                      pending_testing_tag=u'f17-updates-testing-pending',
                      pending_stable_tag=u'f17-updates-pending',
                      override_tag=u'f17-override',
                      branch=u'f17',
                      state=ReleaseState.current)
    db.add(release)
    db.flush()
    update = create_update(db, [u'bodhi-2.0-1.fc17'])
    update.type = UpdateType.bugfix
    update.severity = UpdateSeverity.medium
    bug = Bug(bug_id=12345)
    db.add(bug)
    update.bugs.append(bug)
    cve = CVE(cve_id=u"CVE-1985-0110")
    db.add(cve)
    update.cves.append(cve)

    comment = Comment(karma=1, text=u"wow. amaze.")
    db.add(comment)
    comment.user = user
    update.comments.append(comment)

    comment = Comment(karma=0, text=u"srsly.  pretty good.", anonymous=True)
    comment.user = anonymous
    db.add(comment)
    update.comments.append(comment)

    with mock.patch(target='uuid.uuid4', return_value='wat'):
        update.assign_alias()
    db.add(update)

    db.commit()
Ejemplo n.º 2
0
def populate(db):
    """
    Create some data for tests to use.

    Args:
        db (sqlalchemy.orm.session.Session): The database session.
    """
    user = User(name='guest')
    db.add(user)
    anonymous = User(name='anonymous')
    db.add(anonymous)
    provenpackager = Group(name='provenpackager')
    db.add(provenpackager)
    packager = Group(name='packager')
    db.add(packager)
    user.groups.append(packager)
    release = Release(name='F17',
                      long_name='Fedora 17',
                      id_prefix='FEDORA',
                      version='17',
                      dist_tag='f17',
                      stable_tag='f17-updates',
                      testing_tag='f17-updates-testing',
                      candidate_tag='f17-updates-candidate',
                      pending_signing_tag='f17-updates-signing-pending',
                      pending_testing_tag='f17-updates-testing-pending',
                      pending_stable_tag='f17-updates-pending',
                      override_tag='f17-override',
                      branch='f17',
                      state=ReleaseState.current,
                      create_automatic_updates=True,
                      package_manager=PackageManager.unspecified,
                      testing_repository=None)
    db.add(release)
    db.flush()
    # This mock will help us generate a consistent update alias.
    with mock.patch(target='uuid.uuid4', return_value='wat'):
        update = create_update(db, ['bodhi-2.0-1.fc17'])
    update.type = UpdateType.bugfix
    update.severity = UpdateSeverity.medium
    bug = Bug(bug_id=12345)
    db.add(bug)
    update.bugs.append(bug)

    comment = Comment(karma=1, text="wow. amaze.")
    db.add(comment)
    comment.user = user
    update.comments.append(comment)

    comment = Comment(karma=0, text="srsly.  pretty good.")
    comment.user = anonymous
    db.add(comment)
    update.comments.append(comment)

    db.add(update)

    db.commit()
Ejemplo n.º 3
0
    def test_list_comments_with_multiple_ignore_user(self):
        another_user = User(name='aUser')
        self.db.add(another_user)
        update = Update(
            user=another_user,
            request=UpdateRequest.testing,
            type=UpdateType.enhancement,
            notes='Just another update.',
            date_submitted=datetime(1981, 10, 11),
            requirements='rpmlint',
            stable_karma=3,
            unstable_karma=-3,
            release=Release.query.one()
        )
        self.db.add(update)

        comment = Comment(karma=1, text='Cool! 😃')
        comment.user = another_user
        self.db.add(comment)
        update.comments.append(comment)
        self.db.flush()

        res = self.app.get('/comments/', {"ignore_user": "******"})
        body = res.json_body
        self.assertEqual(len(body['comments']), 1)
        self.assertNotIn('errors', body)
        self.assertEqual(body['comments'][0]['text'], 'Cool! 😃')
Ejemplo n.º 4
0
    def test_list_comments_by_multiple_usernames(self):
        nvr = u'just-testing-1.0-2.fc17'
        update = Update(
            title=nvr,
            request=UpdateRequest.testing,
            type=UpdateType.enhancement,
            notes=u'Just another update.',
            date_submitted=datetime(1981, 10, 11),
            requirements=u'rpmlint',
            stable_karma=3,
            unstable_karma=-3,
        )
        update.release = Release.query.one()
        self.db.add(update)

        another_user = User(name=u'aUser')
        self.db.add(another_user)

        comment = Comment(karma=1, text=u'Cool! 😃')
        comment.user = another_user
        self.db.add(comment)
        update.comments.append(comment)
        self.db.flush()

        res = self.app.get('/comments/', {"user": "******"})
        body = res.json_body
        self.assertEqual(len(body['comments']), 2)
        self.assertEqual(body['comments'][0]['text'], u'Cool! 😃')
        self.assertEqual(body['comments'][1]['text'], u'wow. amaze.')
Ejemplo n.º 5
0
    def test_list_comments_by_multiple_update_owners(self):
        another_user = User(name='aUser')
        self.db.add(another_user)
        update = Update(
            user=another_user,
            request=UpdateRequest.testing,
            type=UpdateType.enhancement,
            notes='Just another update.',
            date_submitted=datetime(1981, 10, 11),
            requirements='rpmlint',
            stable_karma=3,
            unstable_karma=-3,
            release=Release.query.one()
        )
        self.db.add(update)

        comment = Comment(karma=1, text='Cool! 😃')
        comment.user = another_user
        self.db.add(comment)
        update.comments.append(comment)
        self.db.flush()

        res = self.app.get('/comments/', {"update_owner": "guest,aUser"})
        body = res.json_body
        self.assertEqual(len(body['comments']), 3)

        comment = body['comments'][0]
        self.assertEqual(comment['text'], 'Cool! 😃')
        comment = body['comments'][1]
        self.assertEqual(comment['text'], 'srsly.  pretty good.')
Ejemplo n.º 6
0
    def test_list_comments_by_multiple_usernames(self):
        update = Update(request=UpdateRequest.testing,
                        type=UpdateType.enhancement,
                        notes='Just another update.',
                        date_submitted=datetime(1981, 10, 11),
                        requirements='rpmlint',
                        stable_karma=3,
                        unstable_karma=-3,
                        release=Release.query.one())
        self.db.add(update)

        another_user = User(name='aUser')
        self.db.add(another_user)

        comment = Comment(karma=1, text='Cool! 😃')
        comment.user = another_user
        self.db.add(comment)
        update.comments.append(comment)
        self.db.flush()

        res = self.app.get('/comments/', {"user": "******"})
        body = res.json_body
        assert len(body['comments']) == 2
        assert body['comments'][0]['text'] == 'Cool! 😃'
        assert body['comments'][1]['text'] == 'wow. amaze.'
Ejemplo n.º 7
0
    def setUp(self, *args, **kwargs):
        super(TestCommentsService, self).setUp(*args, **kwargs)

        # Add a second update owned by somebody else so we can test karma
        # policy stuff
        user2 = User(name='lmacken')
        self.db.flush()
        self.db.add(user2)
        release = self.db.query(Release).filter_by(name='F17').one()
        update = Update(
            user=user2,
            request=UpdateRequest.testing,
            type=UpdateType.enhancement,
            notes='Useful details!',
            release=release,
            date_submitted=datetime(1984, 11, 2),
            requirements='rpmlint',
            stable_karma=3,
            unstable_karma=-3,
        )
        self.db.add(update)
        build = RpmBuild(nvr=up2, update=update,
                         package=RpmPackage.query.filter_by(name='bodhi').one())
        self.db.add(build)
        self.db.flush()
Ejemplo n.º 8
0
    def test_list_overrides_by_multiple_usernames(self):
        release = Release.get('F17')

        package = RpmPackage(name='just-testing')
        self.db.add(package)
        build = RpmBuild(nvr='just-testing-1.0-2.fc17', package=package, release=release)
        self.db.add(build)
        another_user = User(name='aUser')
        self.db.add(another_user)

        expiration_date = datetime.utcnow() + timedelta(days=1)

        override = BuildrootOverride(build=build, submitter=another_user,
                                     notes='Crazy! 😱',
                                     expiration_date=expiration_date)
        self.db.add(override)
        self.db.flush()

        res = self.app.get('/overrides/', {"user": "******"})
        body = res.json_body
        self.assertEqual(len(body['overrides']), 2)

        override_fake = body['overrides'][0]
        self.assertEqual(override_fake['build']['nvr'], 'just-testing-1.0-2.fc17')
        self.assertEqual(override_fake['submitter']['name'], 'aUser')
        self.assertEqual(override_fake['notes'], 'Crazy! 😱')

        override_orig = body['overrides'][1]
        self.assertEqual(override_orig['build']['nvr'], 'bodhi-2.0-1.fc17')
        self.assertEqual(override_orig['submitter']['name'], 'guest')
        self.assertEqual(override_orig['notes'], 'blah blah blah')
Ejemplo n.º 9
0
 def test_list_comments_by_update_owner_with_none(self):
     user = User(name='ralph')
     self.db.add(user)
     self.db.flush()
     res = self.app.get('/comments/', {"update_owner": "ralph"})
     body = res.json_body
     self.assertEqual(len(body['comments']), 0)
     self.assertNotIn('errors', body)
Ejemplo n.º 10
0
    def test_list_overrides_by_username_without_override(self):
        self.db.add(User(name='bochecha'))
        self.db.flush()

        res = self.app.get('/overrides/', {'user': '******'})

        body = res.json_body
        self.assertEqual(len(body['overrides']), 0)
Ejemplo n.º 11
0
    def test_get_single_user_with_nonstandard_characters(self):
        """Test that we don't receive a 404 page with bot usernames."""
        user = User(name='bot/a.bad.name')
        self.db.add(user)
        self.db.flush()

        res = self.app.get('/users/bot/a.bad.name')
        assert res.json_body['user']['name'] == 'bot/a.bad.name'
Ejemplo n.º 12
0
 def test_list_comments_by_update_owner_with_none(self):
     user = User(name='ralph')
     self.db.add(user)
     self.db.flush()
     res = self.app.get('/comments/', {"update_owner": "ralph"})
     body = res.json_body
     assert len(body['comments']) == 0
     assert 'errors' not in body
Ejemplo n.º 13
0
 def test_edit_stack_with_no_user_privs(self, *args):
     user = User(name=u'bob')
     self.db.add(user)
     self.db.add(RpmPackage(name=u'gnome-music'))
     self.db.commit()
     self.stack.users.append(user)
     self.db.commit()
     attrs = {'name': 'GNOME', 'packages': 'gnome-music gnome-shell',
              'csrf_token': self.get_csrf_token()}
     res = self.app.post("/stacks/", attrs, status=403)
     body = res.json_body
     self.assertEquals(body['status'], 'error')
     self.assertEquals(body['errors'][0]['description'],
                       'guest does not have privileges to modify the GNOME stack')
Ejemplo n.º 14
0
    def test_existing_user(self, caplog):
        """Test Koji build user existing in DB."""
        caplog.set_level(logging.DEBUG)

        expected_username = base.buildsys.DevBuildsys._build_data['owner_name']

        # ensure user with expected name exists
        user = self.db.query(User).filter_by(name=expected_username).first()
        if not user:
            user = User(name=expected_username)
            self.db.add(user)
        self.db.flush()

        assert (f"Creating bodhi user for '{expected_username}'."
                not in caplog.messages)
Ejemplo n.º 15
0
def create_or_update_user(db, username, email, groups):
    """Create or update a user in the database.

    Args:
        db (sqlalchemy.orm.session.Session): The database session.
        username (str): The username to create or update
        email (str): The user's email address
        groups (list(str)): A list of group names the user belongs to, that will be synced.

    Returns:
        bodhi.server.models.User: The user instance.
    """
    # Find the user in our database. Create it if it doesn't exist.
    user = db.query(User).filter_by(name=username).first()
    if not user:
        user = User(name=username, email=email)
        db.add(user)
        db.flush()
    else:
        # Update email address if the address changed
        if user.email != email:
            user.email = email
            db.flush()

    # Keep track of what groups the user is a member of
    for group_name in groups:
        # Drop empty group names https://github.com/fedora-infra/bodhi/issues/306
        if not group_name.strip():
            continue

        group = db.query(Group).filter_by(name=group_name).first()
        if not group:
            group = Group(name=group_name)
            db.add(group)
            db.flush()
        if group not in user.groups:
            log.info('Adding %s to %s group', user.name, group.name)
            user.groups.append(group)

    # See if the user was removed from any groups
    for group in user.groups:
        if group.name not in groups:
            log.info('Removing %s from %s group', user.name, group.name)
            user.groups.remove(group)

    return user
Ejemplo n.º 16
0
    def test_existing_user(self, caplog):
        """Test Koji build user existing in DB."""
        caplog.set_level(logging.DEBUG)

        expected_username = base.buildsys.DevBuildsys._build_data['owner_name']

        # ensure user with expected name exists
        user = self.db.query(User).filter_by(name=expected_username).first()
        if not user:
            user = User(name=expected_username)
            self.db.add(user)
        self.db.flush()

        with mock.patch('bodhi.server.models.handle_update'):
            with mock_sends(update_schemas.UpdateReadyForTestingV1):
                self.handler(self.sample_message)

        assert (f"Creating bodhi user for '{expected_username}'."
                not in caplog.messages)
Ejemplo n.º 17
0
    def setUp(self):
        super(TestUsersService, self).setUp()

        user = User(name=u'bodhi')
        self.db.add(user)
        self.db.flush()
Ejemplo n.º 18
0
    def setUp(self, *args, **kwargs):
        super(TestFrontpageView, self).setUp(*args, **kwargs)

        def _add_updates(updateslist, user, release, packagesuffix):
            """Private method that adds updates to the database for testing

            """
            count = 0
            for i in updateslist:
                for j in i[1]:
                    for k in range(0, j[1]):
                        update = Update(
                            title=u'bodhi-2.0-1%s.%s' %
                            (str(count), packagesuffix),
                            user=user,
                            status=i[0],
                            type=j[0],
                            notes=u'Useful details!',
                            release=release,
                            date_submitted=datetime(1984, 11, 2),
                            requirements=u'rpmlint',
                            stable_karma=3,
                            unstable_karma=-3,
                        )
                        self.db.add(update)
                        self.db.flush()
                        count = count + 1

        user2 = User(name=u'dudemcpants')
        self.db.flush()
        self.db.add(user2)

        release = Release(name=u'F18',
                          long_name=u'Fedora 18',
                          id_prefix=u'FEDORA',
                          version=u'18',
                          dist_tag=u'f18',
                          stable_tag=u'f18-updates',
                          testing_tag=u'f18-updates-testing',
                          candidate_tag=u'f18-updates-candidate',
                          pending_signing_tag=u'f18-updates-testing-signing',
                          pending_testing_tag=u'f18-updates-testing-pending',
                          pending_stable_tag=u'f18-updates-pending',
                          override_tag=u'f18-override',
                          branch=u'f18',
                          state=ReleaseState.pending)
        self.db.add(release)

        currentrelease = self.db.query(Release).filter_by(name=u'F17').one()
        addedupdates = [[
            UpdateStatus.pending,
            [[UpdateType.security, 5], [UpdateType.bugfix, 4],
             [UpdateType.enhancement, 3], [UpdateType.newpackage, 2]]
        ],
                        [
                            UpdateStatus.testing,
                            [[UpdateType.security, 15],
                             [UpdateType.bugfix, 14],
                             [UpdateType.enhancement, 13],
                             [UpdateType.newpackage, 12]]
                        ],
                        [
                            UpdateStatus.stable,
                            [[UpdateType.security, 25],
                             [UpdateType.bugfix, 24],
                             [UpdateType.enhancement, 23],
                             [UpdateType.newpackage, 22]]
                        ]]
        _add_updates(addedupdates, user2, currentrelease, "fc17")

        pendingrelease = self.db.query(Release).filter_by(name=u'F18').one()
        addedupdates2 = [[
            UpdateStatus.pending,
            [[UpdateType.security, 2], [UpdateType.bugfix, 2],
             [UpdateType.enhancement, 2], [UpdateType.newpackage, 2]]
        ],
                         [
                             UpdateStatus.testing,
                             [[UpdateType.security, 3], [UpdateType.bugfix, 3],
                              [UpdateType.enhancement, 3],
                              [UpdateType.newpackage, 3]]
                         ],
                         [
                             UpdateStatus.stable,
                             [[UpdateType.security, 4], [UpdateType.bugfix, 4],
                              [UpdateType.enhancement, 4],
                              [UpdateType.newpackage, 4]]
                         ]]
        _add_updates(addedupdates2, user2, pendingrelease, "fc18")
        self.db.flush()
        Release._tag_cache = None
Ejemplo n.º 19
0
    def setup_method(self, method):
        super(TestUsersService, self).setup_method(method)

        user = User(name='bodhi')
        self.db.add(user)
        self.db.flush()
Ejemplo n.º 20
0
    def __call__(self, message: fedora_messaging.api.Message) -> None:
        """Create updates from appropriately tagged builds.

        Args:
            message: The message we are processing.
        """
        body = message.body

        missing = []
        for mandatory in ('tag', 'build_id', 'name', 'version', 'release'):
            if mandatory not in body:
                missing.append(mandatory)
        if missing:
            log.debug(
                f"Received incomplete tag message. Missing: {', '.join(missing)}"
            )
            return

        btag = body['tag']
        bnvr = '{name}-{version}-{release}'.format(**body)

        koji = buildsys.get_session()

        kbuildinfo = koji.getBuild(bnvr)
        if not kbuildinfo:
            log.debug(f"Can't find Koji build for {bnvr}.")
            return

        if 'nvr' not in kbuildinfo:
            log.debug(f"Koji build info for {bnvr} doesn't contain 'nvr'.")
            return

        if 'owner_name' not in kbuildinfo:
            log.debug(
                f"Koji build info for {bnvr} doesn't contain 'owner_name'.")
            return

        if kbuildinfo['owner_name'] in config.get(
                'automatic_updates_blacklist'):
            log.debug(
                f"{bnvr} owned by {kbuildinfo['owner_name']} who is listed in "
                "automatic_updates_blacklist, skipping.")
            return

        # some APIs want the Koji build info, some others want the same
        # wrapped in a larger (request?) structure
        rbuildinfo = {
            'info': kbuildinfo,
            'nvr': kbuildinfo['nvr'].rsplit('-', 2),
        }

        with self.db_factory() as dbsession:
            rel = dbsession.query(Release).filter_by(
                create_automatic_updates=True, candidate_tag=btag).first()
            if not rel:
                log.debug(
                    f"Ignoring build being tagged into {btag!r}, no release configured for "
                    "automatic updates for it found.")
                return

            bcls = ContentType.infer_content_class(Build, kbuildinfo)
            build = bcls.get(bnvr)
            if build and build.update:
                log.info(
                    f"Build, active update for {bnvr} exists already, skipping."
                )
                return

            if not build:
                log.debug(f"Build for {bnvr} doesn't exist yet, creating.")

                # Package.get_or_create() infers content type already
                log.debug("Getting/creating related package object.")
                pkg = Package.get_or_create(dbsession, rbuildinfo)

                log.debug("Creating build object, adding it to the DB.")
                build = bcls(nvr=bnvr, package=pkg, release=rel)
                dbsession.add(build)

            owner_name = kbuildinfo['owner_name']
            user = User.get(owner_name)
            if not user:
                log.debug(f"Creating bodhi user for '{owner_name}'.")
                # Leave email, groups blank, these will be filled
                # in or updated when they log into Bodhi next time, see
                # bodhi.server.security:remember_me().
                user = User(name=owner_name)
                dbsession.add(user)

            log.debug(f"Creating new update for {bnvr}.")
            changelog = build.get_changelog(lastupdate=True)
            if changelog:
                notes = f"""Automatic update for {bnvr}.

##### **Changelog**

```
{changelog}
```"""
            else:
                notes = f"Automatic update for {bnvr}."
            update = Update(
                release=rel,
                builds=[build],
                notes=notes,
                type=UpdateType.unspecified,
                stable_karma=3,
                unstable_karma=-3,
                autokarma=False,
                user=user,
                status=UpdateStatus.pending,
            )

            # Comment on the update that it was automatically created.
            update.comment(
                dbsession,
                str("This update was automatically created"),
                author="bodhi",
            )

            update.add_tag(update.release.pending_signing_tag)

            log.debug("Adding new update to the database.")
            dbsession.add(update)

            log.debug("Committing changes to the database.")
            dbsession.commit()
Ejemplo n.º 21
0
    def setUp(self, *args, **kwargs):
        super(TestReleasesHTML, self).setUp(*args, **kwargs)

        def _add_updates(updateslist, user, release, packagesuffix):
            """Private method that adds updates to the database for testing

            """
            count = 0
            for i in updateslist:
                for j in i[1]:
                    for k in range(0, j[1]):
                        update = Update(
                            user=user,
                            status=i[0],
                            type=j[0],
                            notes='Useful details!',
                            release=release,
                            date_submitted=datetime(1984, 11, 2),
                            requirements='rpmlint',
                            stable_karma=3,
                            unstable_karma=-3,
                        )
                        self.db.add(update)
                        self.db.commit()
                        count = count + 1

        user2 = User(name='dudemcpants')
        self.db.flush()
        self.db.add(user2)

        release = Release(name='F18',
                          long_name='Fedora 18',
                          id_prefix='FEDORA',
                          version='18',
                          dist_tag='f18',
                          stable_tag='f18-updates',
                          testing_tag='f18-updates-testing',
                          candidate_tag='f18-updates-candidate',
                          pending_signing_tag='f18-updates-testing-signing',
                          pending_testing_tag='f18-updates-testing-pending',
                          pending_stable_tag='f18-updates-pending',
                          override_tag='f18-override',
                          branch='f18',
                          state=ReleaseState.pending)
        self.db.add(release)

        currentrelease = self.db.query(Release).filter_by(name='F17').one()
        addedupdates = [[
            UpdateStatus.pending,
            [[UpdateType.security, 5], [UpdateType.bugfix, 4],
             [UpdateType.enhancement, 3], [UpdateType.newpackage, 2]]
        ],
                        [
                            UpdateStatus.testing,
                            [[UpdateType.security, 15],
                             [UpdateType.bugfix, 14],
                             [UpdateType.enhancement, 13],
                             [UpdateType.newpackage, 12]]
                        ],
                        [
                            UpdateStatus.stable,
                            [[UpdateType.security, 25],
                             [UpdateType.bugfix, 24],
                             [UpdateType.enhancement, 23],
                             [UpdateType.newpackage, 22]]
                        ]]

        with fml_testing.mock_sends(*[api.Message] * 54):
            _add_updates(addedupdates, user2, currentrelease, "fc17")

        pendingrelease = self.db.query(Release).filter_by(name='F18').one()
        addedupdates2 = [[
            UpdateStatus.pending,
            [[UpdateType.security, 2], [UpdateType.bugfix, 2],
             [UpdateType.enhancement, 2], [UpdateType.newpackage, 2]]
        ],
                         [
                             UpdateStatus.testing,
                             [[UpdateType.security, 3], [UpdateType.bugfix, 3],
                              [UpdateType.enhancement, 3],
                              [UpdateType.newpackage, 3]]
                         ],
                         [
                             UpdateStatus.stable,
                             [[UpdateType.security, 4], [UpdateType.bugfix, 4],
                              [UpdateType.enhancement, 4],
                              [UpdateType.newpackage, 4]]
                         ]]
        with fml_testing.mock_sends(*[api.Message] * 12):
            _add_updates(addedupdates2, user2, pendingrelease, "fc18")
        self.db.flush()
        # Clear the caches
        Release._tag_cache = None
        generic._generate_home_page_stats.invalidate()
Ejemplo n.º 22
0
    def __call__(self, message: fedora_messaging.api.Message) -> None:
        """Create updates from appropriately tagged builds.

        Args:
            message: The message we are processing.
        """
        body = message.body

        missing = []
        for mandatory in ('tag', 'build_id', 'name', 'version', 'release'):
            if mandatory not in body:
                missing.append(mandatory)
        if missing:
            log.debug(
                f"Received incomplete tag message. Missing: {', '.join(missing)}"
            )
            return

        btag = body['tag']
        bnvr = '{name}-{version}-{release}'.format(**body)

        koji = buildsys.get_session()

        kbuildinfo = koji.getBuild(bnvr)
        if not kbuildinfo:
            log.debug(f"Can't find Koji build for {bnvr}.")
            return

        if 'nvr' not in kbuildinfo:
            log.debug(f"Koji build info for {bnvr} doesn't contain 'nvr'.")
            return

        if 'owner_name' not in kbuildinfo:
            log.debug(
                f"Koji build info for {bnvr} doesn't contain 'owner_name'.")
            return

        if kbuildinfo['owner_name'] in config.get(
                'automatic_updates_blacklist'):
            log.debug(
                f"{bnvr} owned by {kbuildinfo['owner_name']} who is listed in "
                "automatic_updates_blacklist, skipping.")
            return

        # some APIs want the Koji build info, some others want the same
        # wrapped in a larger (request?) structure
        rbuildinfo = {
            'info': kbuildinfo,
            'nvr': kbuildinfo['nvr'].rsplit('-', 2),
        }

        with self.db_factory() as dbsession:
            rel = dbsession.query(Release).filter_by(
                create_automatic_updates=True, candidate_tag=btag).first()
            if not rel:
                log.debug(
                    f"Ignoring build being tagged into {btag!r}, no release configured for "
                    "automatic updates for it found.")
                return

            bcls = ContentType.infer_content_class(Build, kbuildinfo)
            build = bcls.get(bnvr)
            if build and build.update:
                log.info(
                    f"Build, active update for {bnvr} exists already, skipping."
                )
                return

            if not build:
                log.debug(f"Build for {bnvr} doesn't exist yet, creating.")

                # Package.get_or_create() infers content type already
                log.debug("Getting/creating related package object.")
                pkg = Package.get_or_create(dbsession, rbuildinfo)

                log.debug("Creating build object, adding it to the DB.")
                build = bcls(nvr=bnvr, package=pkg, release=rel)
                dbsession.add(build)

            owner_name = kbuildinfo['owner_name']
            user = User.get(owner_name)
            if not user:
                log.debug(f"Creating bodhi user for '{owner_name}'.")
                # Leave email, groups blank, these will be filled
                # in or updated when they log into Bodhi next time, see
                # bodhi.server.security:remember_me().
                user = User(name=owner_name)
                dbsession.add(user)

            log.debug(f"Creating new update for {bnvr}.")
            try:
                changelog = build.get_changelog(lastupdate=True)
            except ValueError:
                # Often due to bot-generated builds
                # https://github.com/fedora-infra/bodhi/issues/4146
                changelog = None
            except Exception:
                # Re-raise exception, so that the message can be re-queued
                raise
            closing_bugs = []
            if changelog:
                log.debug("Adding changelog to update notes.")
                notes = f"""Automatic update for {bnvr}.

##### **Changelog**

```
{changelog}
```"""

                if rel.name not in config.get('bz_exclude_rels'):
                    for b in re.finditer(config.get('bz_regex'), changelog,
                                         re.IGNORECASE):
                        idx = int(b.group(1))
                        log.debug(f'Adding bug #{idx} to the update.')
                        bug = Bug.get(idx)
                        if bug is None:
                            bug = Bug(bug_id=idx)
                            dbsession.add(bug)
                            dbsession.flush()
                        if bug not in closing_bugs:
                            closing_bugs.append(bug)
            else:
                notes = f"Automatic update for {bnvr}."
            update = Update(
                release=rel,
                builds=[build],
                bugs=closing_bugs,
                notes=notes,
                type=UpdateType.unspecified,
                stable_karma=3,
                unstable_karma=-3,
                autokarma=False,
                user=user,
                status=UpdateStatus.pending,
                critpath=Update.contains_critpath_component([build],
                                                            rel.branch),
            )

            # Comment on the update that it was automatically created.
            update.comment(
                dbsession,
                str("This update was automatically created"),
                author="bodhi",
            )

            update.add_tag(update.release.pending_signing_tag)

            log.debug("Adding new update to the database.")
            dbsession.add(update)

            log.debug("Flushing changes to the database.")
            dbsession.flush()

            # Obsolete older updates which may be stuck in testing due to failed gating
            try:
                update.obsolete_older_updates(dbsession)
            except Exception as e:
                log.error(f'Problem obsoleting older updates: {e}')

            alias = update.alias
            buglist = [b.bug_id for b in update.bugs]

        # This must be run after dbsession is closed so changes are committed to db
        work_on_bugs_task.delay(alias, buglist)