Blame scripts/update_releasenotes.py

Packit Service 21c75c
#!/usr/bin/python2
Packit Service 21c75c
#
Packit Service 21c75c
# Copyright (C) 2015 Red Hat, Inc.
Packit Service 21c75c
#
Packit Service 21c75c
# This copyrighted material is made available to anyone wishing to use,
Packit Service 21c75c
# modify, copy, or redistribute it subject to the terms and conditions of
Packit Service 21c75c
# the GNU General Public License v.2, or (at your option) any later version.
Packit Service 21c75c
# This program is distributed in the hope that it will be useful, but WITHOUT
Packit Service 21c75c
# ANY WARRANTY expressed or implied, including the implied warranties of
Packit Service 21c75c
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
Packit Service 21c75c
# Public License for more details.  You should have received a copy of the
Packit Service 21c75c
# GNU General Public License along with this program; if not, write to the
Packit Service 21c75c
# Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
Packit Service 21c75c
# 02110-1301, USA.  Any Red Hat trademarks that are incorporated in the
Packit Service 21c75c
# source code or documentation are not subject to the GNU General Public
Packit Service 21c75c
# License and may only be used or replicated with the express permission of
Packit Service 21c75c
# Red Hat, Inc.
Packit Service 21c75c
#
Packit Service 21c75c
Packit Service 21c75c
r"""A script intended to update release notes.
Packit Service 21c75c
Packit Service 21c75c
Works on Python >= 2.7 and < 3.0.
Packit Service 21c75c
Packit Service 21c75c
This module, when run as a script, provides a command line interface.
Packit Service 21c75c
The interface usage is::
Packit Service 21c75c
Packit Service 21c75c
    usage: prog [-h]
Packit Service 21c75c
Packit Service 21c75c
    Extend the list of issues of the next version in release notes. It
Packit Service 21c75c
    updates the release notes found in the DNF repository which contains
Packit Service 21c75c
    this module. The module location is obtained from the __file__
Packit Service 21c75c
    variable. The version number is parsed from the spec file. If the
Packit Service 21c75c
    release notes already contains given issue, it is not added again.
Packit Service 21c75c
    Otherwise, it is added to the beginning of the list. If the release
Packit Service 21c75c
    notes does not contain the next version, a new section is appended
Packit Service 21c75c
    right before the first section. The diff between the new release
Packit Service 21c75c
    notes and the Git index is printed to the standard error stream. The
Packit Service 21c75c
    message starts with "INFO Update finished. See the diff to the Git
Packit Service 21c75c
    index: ".
Packit Service 21c75c
Packit Service 21c75c
    optional arguments:
Packit Service 21c75c
      -h, --help  show this help message and exit
Packit Service 21c75c
Packit Service 21c75c
    If the version is already released or if another error occurs the
Packit Service 21c75c
    exit status is non-zero.
Packit Service 21c75c
Packit Service 21c75c
:var LOGGER: the logger used by this script
Packit Service 21c75c
:type LOGGER: logging.Logger
Packit Service 21c75c
:var SPEC_FN: a name of the DNF spec file relative to the working
Packit Service 21c75c
   directory of the Git repository which contains this script
Packit Service 21c75c
:type SPEC_FN: str
Packit Service 21c75c
:var TAG_PAT: a string pattern of DNF tags where the "{version}" field
Packit Service 21c75c
   should be replaced with the given version of DNF
Packit Service 21c75c
:type TAG_PAT: str
Packit Service 21c75c
:var ISSUE_RE: a regular expression matching numbers of resolved issues
Packit Service 21c75c
   in the first line of a commit message
Packit Service 21c75c
:type ISSUE_RE: re.RegexObject
Packit Service 21c75c
:var RELATED_RE: a regular expression matching numbers of related issues
Packit Service 21c75c
   in a commit message
Packit Service 21c75c
:type RELATED_RE: re.RegexObject
Packit Service 21c75c
:var SIMILAR_RE: a regular expression matching numbers which look like a
Packit Service 21c75c
   number of an issue referred in a commit message
Packit Service 21c75c
:type SIMILAR_RE: re.RegexObject
Packit Service 21c75c
:var NOTES_FN: a name of the DNF release notes file relative to the
Packit Service 21c75c
   working directory of the Git repository which contains this script
Packit Service 21c75c
:type NOTES_FN: str
Packit Service 21c75c
:var TITLE_PAT: a string pattern of a DNF release notes section title
Packit Service 21c75c
   (including a trailing "\n") where the "{version}" field should be
Packit Service 21c75c
   replaced with the given release version
Packit Service 21c75c
:type TITLE_PAT: str
Packit Service 21c75c
:var ISSUE_PAT: a string pattern of a reference to a resolved issue in
Packit Service 21c75c
   DNF release notes (including a trailing "\n") where the "{number}"
Packit Service 21c75c
   field should be replaced with the number of the given issue
Packit Service 21c75c
:type ISSUE_PAT: str
Packit Service 21c75c
:var OVERLINE_RE: a regular expression matching a section title overline
Packit Service 21c75c
   in a line of DNF release notes
Packit Service 21c75c
:type OVERLINE_RE: re.RegexObject
Packit Service 21c75c
:var TITLE_RE_PAT: a string pattern of a regular expression matching a
Packit Service 21c75c
   section title in a line of DNF release notes where the "{maxlen}"
Packit Service 21c75c
   field should be replaced with the maximum expected length of the
Packit Service 21c75c
   release version
Packit Service 21c75c
:type TITLE_RE_PAT: str
Packit Service 21c75c
Packit Service 21c75c
"""
Packit Service 21c75c
Packit Service 21c75c
Packit Service 21c75c
from __future__ import absolute_import
Packit Service 21c75c
Packit Service 21c75c
import argparse
Packit Service 21c75c
import contextlib
Packit Service 21c75c
import io
Packit Service 21c75c
import itertools
Packit Service 21c75c
import logging
Packit Service 21c75c
import os
Packit Service 21c75c
import re
Packit Service 21c75c
import shutil
Packit Service 21c75c
import sys
Packit Service 21c75c
import tempfile
Packit Service 21c75c
import unittest
Packit Service 21c75c
Packit Service 21c75c
import git
Packit Service 21c75c
import rpm
Packit Service 21c75c
import tests.mock
Packit Service 21c75c
Packit Service 21c75c
Packit Service 21c75c
LOGGER = logging.getLogger(sys.argv[0])
Packit Service 21c75c
Packit Service 21c75c
SPEC_FN = 'dnf.spec'
Packit Service 21c75c
Packit Service 21c75c
TAG_PAT = 'dnf-{version}-1'
Packit Service 21c75c
Packit Service 21c75c
ISSUE_RE = re.compile(ur'(?
Packit Service 21c75c
Packit Service 21c75c
RELATED_RE = re.compile(ur'Related: RhBug:(\d+)')
Packit Service 21c75c
Packit Service 21c75c
SIMILAR_RE = re.compile(ur'\d{6,}')
Packit Service 21c75c
Packit Service 21c75c
NOTES_FN = os.path.join('doc', 'release_notes.rst')
Packit Service 21c75c
Packit Service 21c75c
TITLE_PAT = '{version} Release Notes\n'
Packit Service 21c75c
Packit Service 21c75c
ISSUE_PAT = '* :rhbug:`{number}`\n'
Packit Service 21c75c
Packit Service 21c75c
OVERLINE_RE = re.compile('^(=+)\n$')
Packit Service 21c75c
Packit Service 21c75c
TITLE_RE_PAT = '^(.{{,{maxlen}}}) Release Notes\n$'
Packit Service 21c75c
Packit Service 21c75c
Packit Service 21c75c
@contextlib.contextmanager
Packit Service 21c75c
def _safe_overwrite(name):
Packit Service 21c75c
    """Open a file in order to overwrite it safely.
Packit Service 21c75c
Packit Service 21c75c
    Until the context manager successfully exits, the file remains
Packit Service 21c75c
    unchanged.
Packit Service 21c75c
Packit Service 21c75c
    :param name: name of the file
Packit Service 21c75c
    :type name: str
Packit Service 21c75c
    :returns: a context manager that returns a readable text file object
Packit Service 21c75c
        intended to read the content of the file and a writable text
Packit Service 21c75c
        file object intended to write the new content of the file
Packit Service 21c75c
    :rtype: contextmanager[tuple[file, file]]
Packit Service 21c75c
    :raises exceptions.IOError: if the file cannot be opened
Packit Service 21c75c
Packit Service 21c75c
    """
Packit Service 21c75c
    with open(name, 'rt+') as file_, tempfile.TemporaryFile('wt+') as tmpfile:
Packit Service 21c75c
        yield file_, tmpfile
Packit Service 21c75c
        tmpfile.seek(0)
Packit Service 21c75c
        file_.seek(0)
Packit Service 21c75c
        shutil.copyfileobj(tmpfile, file_)
Packit Service 21c75c
Packit Service 21c75c
Packit Service 21c75c
def detect_repository():
Packit Service 21c75c
    """Detect the DNF Git repository which contains this module.
Packit Service 21c75c
Packit Service 21c75c
    The module location is obtained from :const:`__file__`.
Packit Service 21c75c
Packit Service 21c75c
    :returns: the repository
Packit Service 21c75c
    :rtype: git.Repo
Packit Service 21c75c
Packit Service 21c75c
    """
Packit Service 21c75c
    dirname = os.path.dirname(__file__)
Packit Service 21c75c
    # FIXME remove this once we can get rid of supporting GitPython < 0.3.5
Packit Service 21c75c
    try:
Packit Service 21c75c
        return git.Repo(dirname, search_parent_directories=True)
Packit Service 21c75c
    except TypeError:
Packit Service 21c75c
        return git.Repo(dirname)
Packit Service 21c75c
Packit Service 21c75c
Packit Service 21c75c
def detect_version(repository):
Packit Service 21c75c
    """Detect the DNF version from its spec file.
Packit Service 21c75c
Packit Service 21c75c
    :param repository: a non-bare DNF repository which contains the spec
Packit Service 21c75c
       file
Packit Service 21c75c
    :type repository: git.Repo
Packit Service 21c75c
    :returns: the detected version
Packit Service 21c75c
    :rtype: str
Packit Service 21c75c
Packit Service 21c75c
    """
Packit Service 21c75c
    filename = os.path.join(repository.working_dir, SPEC_FN)
Packit Service 21c75c
    return rpm.spec(filename).sourceHeader[rpm.RPMTAG_VERSION]
Packit Service 21c75c
Packit Service 21c75c
Packit Service 21c75c
def find_tag(repository, version):
Packit Service 21c75c
    """Find the Git tag corresponding to a DNF version.
Packit Service 21c75c
Packit Service 21c75c
    :param repository: a DNF repository
Packit Service 21c75c
    :type repository: git.Repo
Packit Service 21c75c
    :returns: the name of the tag
Packit Service 21c75c
    :rtype: str | None
Packit Service 21c75c
Packit Service 21c75c
    """
Packit Service 21c75c
    tagname = TAG_PAT.format(version=version)
Packit Service 21c75c
    return tagname if tagname in repository.tags else None
Packit Service 21c75c
Packit Service 21c75c
Packit Service 21c75c
def iter_unreleased_commits(repository):
Packit Service 21c75c
    """Iterate over the commits that were not tagged as a release.
Packit Service 21c75c
Packit Service 21c75c
    :param repository: a repository
Packit Service 21c75c
    :type repository: git.Repo
Packit Service 21c75c
    :returns: a generator yielding the commits
Packit Service 21c75c
    :rtype: generator[git.Commit]
Packit Service 21c75c
Packit Service 21c75c
    """
Packit Service 21c75c
    tagshas = {tag.commit.hexsha for tag in repository.tags}
Packit Service 21c75c
    for commit in repository.iter_commits():
Packit Service 21c75c
        if commit.hexsha in tagshas:
Packit Service 21c75c
            # FIXME encode() once we get rid of supporting GitPython < 0.3.4
Packit Service 21c75c
            LOGGER.debug(
Packit Service 21c75c
                'Unreleased commits iteration stopped on the first tagged '
Packit Service 21c75c
                'commit: %s', commit.hexsha.encode())
Packit Service 21c75c
            break
Packit Service 21c75c
        yield commit
Packit Service 21c75c
Packit Service 21c75c
Packit Service 21c75c
def parse_issues(commits):
Packit Service 21c75c
    """Parse the numbers of the resolved DNF issues from commit messages.
Packit Service 21c75c
Packit Service 21c75c
    :param commits: the DNF commits
Packit Service 21c75c
    :type commits: collections.Iterable[git.Commit]
Packit Service 21c75c
    :returns: a generator yielding the issue numbers
Packit Service 21c75c
    :rtype: generator[str]
Packit Service 21c75c
Packit Service 21c75c
    """
Packit Service 21c75c
    for commit in commits:
Packit Service 21c75c
        firstline = commit.message.splitlines()[0]
Packit Service 21c75c
        valid = {match.group(1) for match in ISSUE_RE.finditer(firstline)}
Packit Service 21c75c
        for issue in valid:
Packit Service 21c75c
            issue = issue.encode()
Packit Service 21c75c
            # FIXME decode() once we get rid of supporting GitPython < 0.3.4
Packit Service 21c75c
            LOGGER.debug(
Packit Service 21c75c
                'Recognized %s in commit %s.', issue,
Packit Service 21c75c
                commit.hexsha.decode().encode())
Packit Service 21c75c
            yield issue.encode()
Packit Service 21c75c
        valid |= {mat.group(1) for mat in RELATED_RE.finditer(commit.message)}
Packit Service 21c75c
        for match in SIMILAR_RE.finditer(commit.message):
Packit Service 21c75c
            if match.group(0) not in valid:
Packit Service 21c75c
                # FIXME decode once we get rid of supporting GitPython < 0.3.4
Packit Service 21c75c
                LOGGER.warning(
Packit Service 21c75c
                    'Skipped %s in commit %s which looks like an issue '
Packit Service 21c75c
                    'number.', match.group(0).encode(),
Packit Service 21c75c
                    commit.hexsha.decode().encode())
Packit Service 21c75c
Packit Service 21c75c
Packit Service 21c75c
def extend_releases(releases, version, issues):
Packit Service 21c75c
    r"""Extend the list of issues of a release version in release notes.
Packit Service 21c75c
Packit Service 21c75c
    The issues are appended to the beginning of the list. If an issue is
Packit Service 21c75c
    already in the list of the release version, it is not added again.
Packit Service 21c75c
    If the release version is not found, the release version
Packit Service 21c75c
    (``version, '\n', issues, '\n'``) is yielded right before the first
Packit Service 21c75c
    release version in the release notes.
Packit Service 21c75c
Packit Service 21c75c
    :param releases: the version, the description, the list of issue
Packit Service 21c75c
       numbers and the epilog for each release version in release notes
Packit Service 21c75c
    :type releases: collections.Iterable[tuple[str | None, str, list[str], str]]
Packit Service 21c75c
    :param version: the release version to be extended
Packit Service 21c75c
    :type version: str
Packit Service 21c75c
    :param issues: the issues to be added
Packit Service 21c75c
    :type issues: collections.Iterable[str]
Packit Service 21c75c
    :returns: a generator yielding the modified release notes
Packit Service 21c75c
    :rtype:  generator[tuple[str | None, str, list[str], str]]
Packit Service 21c75c
Packit Service 21c75c
    """
Packit Service 21c75c
    releases, issues = list(releases), list(issues)
Packit Service 21c75c
    prepend = not any(release[0] == version for release in releases)
Packit Service 21c75c
    for version_, description, issues_, epilog in releases:
Packit Service 21c75c
        if prepend and version_ is not None:
Packit Service 21c75c
            yield version, '\n', issues, '\n'
Packit Service 21c75c
            prepend = False
Packit Service 21c75c
        elif version_ == version:
Packit Service 21c75c
            issues_ = issues_[:]
Packit Service 21c75c
            for issue in reversed(issues):
Packit Service 21c75c
                if issue not in issues_:
Packit Service 21c75c
                    issues_.insert(0, issue)
Packit Service 21c75c
        yield version_, description, issues_, epilog
Packit Service 21c75c
Packit Service 21c75c
Packit Service 21c75c
def format_release(version, description, issues, epilog):
Packit Service 21c75c
    """Compose a string in form of DNF release notes from a release.
Packit Service 21c75c
Packit Service 21c75c
    The order of issues is preserved.
Packit Service 21c75c
Packit Service 21c75c
    :param version: the version of the release
Packit Service 21c75c
    :type version: str | None
Packit Service 21c75c
    :param description: the description of the release
Packit Service 21c75c
    :type description: str
Packit Service 21c75c
    :param issues: the list of issue numbers of the release
Packit Service 21c75c
    :type issues: list[str]
Packit Service 21c75c
    :param epilog: the epilog of the release
Packit Service 21c75c
    :type epilog: str
Packit Service 21c75c
    :returns: the formatted string
Packit Service 21c75c
    :rtype: str
Packit Service 21c75c
Packit Service 21c75c
    """
Packit Service 21c75c
    titlestr = ''
Packit Service 21c75c
    if version:
Packit Service 21c75c
        title = TITLE_PAT.format(version=version)
Packit Service 21c75c
        length = len(title) - 1
Packit Service 21c75c
        titlestr = '{}\n{}{}\n'.format('=' * length, title, '=' * length)
Packit Service 21c75c
    issuestr = ''.join(ISSUE_PAT.format(number=issue) for issue in issues)
Packit Service 21c75c
    return ''.join([titlestr, description, issuestr, epilog])
Packit Service 21c75c
Packit Service 21c75c
Packit Service 21c75c
def update_notes():
Packit Service 21c75c
    r"""Extend the list of issues of the next version in release notes.
Packit Service 21c75c
Packit Service 21c75c
    It updates the release notes found in the DNF repository which
Packit Service 21c75c
    contains this module. The module location is obtained from
Packit Service 21c75c
    :const:`__file__`. The version number is parsed from the spec file.
Packit Service 21c75c
    If the release notes already contains given issue, it is not added
Packit Service 21c75c
    again. Otherwise, it is added to the beginning of the list. If the
Packit Service 21c75c
    release notes does not contain the next version, a new section is
Packit Service 21c75c
    appended right before the first section. The diff between the new
Packit Service 21c75c
    release notes and the Git index is logged to :const:`.LOGGER` with
Packit Service 21c75c
    level :const:`INFO`. The message starts with "Update finished. See
Packit Service 21c75c
    the diff to the Git index:\n".
Packit Service 21c75c
Packit Service 21c75c
    :raises exceptions.ValueError: if the version is already released
Packit Service 21c75c
Packit Service 21c75c
    """
Packit Service 21c75c
    repository = detect_repository()
Packit Service 21c75c
    LOGGER.info('Detected the repository at: %s', repository.working_dir)
Packit Service 21c75c
    notesfn = os.path.join(repository.working_dir, NOTES_FN)
Packit Service 21c75c
    version = detect_version(repository)
Packit Service 21c75c
    LOGGER.info('Detected DNF version (from the spec file): %s', version)
Packit Service 21c75c
    issues = parse_issues(iter_unreleased_commits(repository))
Packit Service 21c75c
    parser = ReleaseNotesParser()
Packit Service 21c75c
    tagname = find_tag(repository, version)
Packit Service 21c75c
    if tagname:
Packit Service 21c75c
        LOGGER.warning('Found a tag matching the current version: %s', tagname)
Packit Service 21c75c
        LOGGER.error('Extending an already released version is not allowed!')
Packit Service 21c75c
        raise ValueError('version already released')
Packit Service 21c75c
    with _safe_overwrite(notesfn) as (source, destination):
Packit Service 21c75c
        releases = extend_releases(parser.parse_lines(source), version, issues)
Packit Service 21c75c
        for version_, desc, issues_, epilog in releases:
Packit Service 21c75c
            destination.write(format_release(version_, desc, issues_, epilog))
Packit Service 21c75c
    diff = repository.index.diff(None, NOTES_FN, create_patch=True)[0].diff
Packit Service 21c75c
    LOGGER.info(
Packit Service 21c75c
        'Update finished. See the diff to the Git index:\n%s',
Packit Service 21c75c
        re.sub(r'^', '    ', diff, flags=re.M))
Packit Service 21c75c
Packit Service 21c75c
Packit Service 21c75c
def main():
Packit Service 21c75c
    """Start the main loop of the command line interface.
Packit Service 21c75c
Packit Service 21c75c
    The root logger is configured to write DEBUG+ messages into the
Packit Service 21c75c
    directory where is this module located if not configured otherwise.
Packit Service 21c75c
    A handler that writes INFO+ messages to :data:`sys.stderr` is added
Packit Service 21c75c
    to :const:`.LOGGER`.
Packit Service 21c75c
Packit Service 21c75c
    The interface usage is::
Packit Service 21c75c
Packit Service 21c75c
        usage: prog [-h]
Packit Service 21c75c
Packit Service 21c75c
        Extend the list of issues of the next version in release notes.
Packit Service 21c75c
        It updates the release notes found in the DNF repository which
Packit Service 21c75c
        contains this module. The module location is obtained from the
Packit Service 21c75c
        __file__ variable. The version number is parsed from the spec
Packit Service 21c75c
        file. If the release notes already contains given issue, it is
Packit Service 21c75c
        not added again. Otherwise, it is added to the beginning of the
Packit Service 21c75c
        list. If the release notes does not contain the next version, a
Packit Service 21c75c
        new section is appended right before the first section. The diff
Packit Service 21c75c
        between the new release notes and the Git index is printed to
Packit Service 21c75c
        the standard error stream. The message starts with "INFO Update
Packit Service 21c75c
        finished. See the diff to the Git index: ".
Packit Service 21c75c
Packit Service 21c75c
        optional arguments:
Packit Service 21c75c
          -h, --help  show this help message and exit
Packit Service 21c75c
Packit Service 21c75c
        If the version is already released or if another error occurs
Packit Service 21c75c
        the exit status is non-zero.
Packit Service 21c75c
Packit Service 21c75c
    :raises exceptions.SystemExit: with a non-zero exit status if an
Packit Service 21c75c
       error occurs
Packit Service 21c75c
Packit Service 21c75c
    """
Packit Service 21c75c
    logging.basicConfig(
Packit Service 21c75c
        filename='{}.log'.format(__file__),
Packit Service 21c75c
        filemode='wt',
Packit Service 21c75c
        format='%(asctime)s.%(msecs)03d:%(levelname)s:%(name)s:%(message)s',
Packit Service 21c75c
        datefmt='%Y%m%dT%H%M%S',
Packit Service 21c75c
        level=logging.DEBUG)
Packit Service 21c75c
    handler = logging.StreamHandler()
Packit Service 21c75c
    handler.setLevel(logging.INFO)
Packit Service 21c75c
    handler.setFormatter(logging.Formatter('%(levelname)s %(message)s'))
Packit Service 21c75c
    LOGGER.addHandler(handler)
Packit Service 21c75c
    argparser = argparse.ArgumentParser(
Packit Service 21c75c
        description='Extend the list of issues of the next version in release '
Packit Service 21c75c
                    'notes. It updates the release notes found in the DNF '
Packit Service 21c75c
                    'repository which contains this module. The module '
Packit Service 21c75c
                    'location is obtained from the __file__ variable. The '
Packit Service 21c75c
                    'version number is parsed from the spec file. If the '
Packit Service 21c75c
                    'release notes already contains given issue, it is not '
Packit Service 21c75c
                    'added again. Otherwise, it is added to the beginning of '
Packit Service 21c75c
                    'the list. If the release notes does not contain the next '
Packit Service 21c75c
                    'version, a new section is appended right before the first'
Packit Service 21c75c
                    ' section. The diff between the new release notes and the '
Packit Service 21c75c
                    'Git index is printed to the standard error stream. The '
Packit Service 21c75c
                    'message starts with "INFO Update finished. See the diff '
Packit Service 21c75c
                    'to the Git index:\n".',
Packit Service 21c75c
        epilog='If the version is already released or if another error occurs '
Packit Service 21c75c
               'the exit status is non-zero.')
Packit Service 21c75c
    argparser.parse_args()
Packit Service 21c75c
    try:
Packit Service 21c75c
        update_notes()
Packit Service 21c75c
    except ValueError:
Packit Service 21c75c
        sys.exit(1)
Packit Service 21c75c
Packit Service 21c75c
Packit Service 21c75c
class ReleaseNotesParser(object):
Packit Service 21c75c
Packit Service 21c75c
    """A class able to parse DNF release notes.
Packit Service 21c75c
Packit Service 21c75c
    :ivar _needline: an expected line which represents the end of a
Packit Service 21c75c
       section title
Packit Service 21c75c
    :type _needline: str | None
Packit Service 21c75c
    :ivar _version: a version parsed from a potential next section title
Packit Service 21c75c
    :type _version: str | None
Packit Service 21c75c
    :ivar version: a version parsed from the last section title
Packit Service 21c75c
    :type version: str | None
Packit Service 21c75c
    :ivar description: lines parsed from the last section description
Packit Service 21c75c
    :type description: list[str]
Packit Service 21c75c
    :ivar issues: numbers of resolved issues parsed from the last
Packit Service 21c75c
       section
Packit Service 21c75c
    :type issues: list[str]
Packit Service 21c75c
    :ivar epilog: lines parsed from the last section epilog
Packit Service 21c75c
    :type epilog: list[str]
Packit Service 21c75c
Packit Service 21c75c
    """
Packit Service 21c75c
Packit Service 21c75c
    def __init__(self):
Packit Service 21c75c
        """Initialize the parser."""
Packit Service 21c75c
        super(ReleaseNotesParser, self).__init__()
Packit Service 21c75c
        self._needline = None
Packit Service 21c75c
        self._version = None
Packit Service 21c75c
        self.version = None
Packit Service 21c75c
        self.description = []
Packit Service 21c75c
        self.issues = []
Packit Service 21c75c
        self.epilog = []
Packit Service 21c75c
Packit Service 21c75c
    @property
Packit Service 21c75c
    def _last_version(self):
Packit Service 21c75c
        """The last parsed release version.
Packit Service 21c75c
Packit Service 21c75c
        :returns: the version, the description, the list of issue
Packit Service 21c75c
           numbers and the epilog of the release
Packit Service 21c75c
        :rtype: tuple[str | None, str, list[str], str]
Packit Service 21c75c
Packit Service 21c75c
        """
Packit Service 21c75c
        return (
Packit Service 21c75c
            self.version,
Packit Service 21c75c
            ''.join(self.description),
Packit Service 21c75c
            self.issues,
Packit Service 21c75c
            ''.join(self.epilog))
Packit Service 21c75c
Packit Service 21c75c
    def _cancel_title(self):
Packit Service 21c75c
        """Cancel expectations of a next section title.
Packit Service 21c75c
Packit Service 21c75c
        It modifies :attr:`_needline` and :attr:`_version`.
Packit Service 21c75c
Packit Service 21c75c
        :returns: the old values of :attr:`_needline` and
Packit Service 21c75c
           :attr:`_version`
Packit Service 21c75c
        :rtype: tuple[str | None, str | None]
Packit Service 21c75c
Packit Service 21c75c
        """
Packit Service 21c75c
        needline, version = self._needline, self._version
Packit Service 21c75c
        self._needline = self._version = None
Packit Service 21c75c
        return needline, version
Packit Service 21c75c
Packit Service 21c75c
    def _parse_overline(self, line):
Packit Service 21c75c
        """Parse the overline of the next section title from a line.
Packit Service 21c75c
Packit Service 21c75c
        It changes the state of the parser.
Packit Service 21c75c
Packit Service 21c75c
        :param line: the line to be parsed
Packit Service 21c75c
        :type line: str
Packit Service 21c75c
        :returns: returns :data:`True` if the line contains an
Packit Service 21c75c
            overline, otherwise it returns :data:`False`
Packit Service 21c75c
        :rtype: bool
Packit Service 21c75c
Packit Service 21c75c
        """
Packit Service 21c75c
        match = OVERLINE_RE.match(line)
Packit Service 21c75c
        if not match:
Packit Service 21c75c
            return False
Packit Service 21c75c
        self._cancel_title()
Packit Service 21c75c
        self._needline = match.group(1)
Packit Service 21c75c
        return True
Packit Service 21c75c
Packit Service 21c75c
    def _parse_title(self, line):
Packit Service 21c75c
        """Parse the title from a line.
Packit Service 21c75c
Packit Service 21c75c
        It changes the state of the parser even if the line does not
Packit Service 21c75c
        contain a title.
Packit Service 21c75c
Packit Service 21c75c
        :param line: the line to be parsed
Packit Service 21c75c
        :type line: str
Packit Service 21c75c
        :returns: returns :data:`True` if the line contains a title,
Packit Service 21c75c
           otherwise it returns :data:`False`
Packit Service 21c75c
        :rtype: bool
Packit Service 21c75c
Packit Service 21c75c
        """
Packit Service 21c75c
        maxlen = len(self._needline) - len(' Release Notes')
Packit Service 21c75c
        match = re.match(TITLE_RE_PAT.format(maxlen=maxlen), line)
Packit Service 21c75c
        if not match:
Packit Service 21c75c
            self._cancel_title()
Packit Service 21c75c
            return False
Packit Service 21c75c
        self._version = match.group(1)
Packit Service 21c75c
        return True
Packit Service 21c75c
Packit Service 21c75c
    def _parse_underline(self, line):
Packit Service 21c75c
        """Parse the underline of the next section title from a line.
Packit Service 21c75c
Packit Service 21c75c
        It changes the state of the parser.
Packit Service 21c75c
Packit Service 21c75c
        :param line: the line to be parsed
Packit Service 21c75c
        :type line: str
Packit Service 21c75c
        :returns: the version, the description, the list of issue
Packit Service 21c75c
           numbers and the epilog of the previous release
Packit Service 21c75c
        :rtype: tuple[str | None, str, list[str], str] | None
Packit Service 21c75c
Packit Service 21c75c
        """
Packit Service 21c75c
        needline, version = self._cancel_title()
Packit Service 21c75c
        if line != '{}\n'.format(needline):
Packit Service 21c75c
            return None
Packit Service 21c75c
        previous_version = self._last_version
Packit Service 21c75c
        self.version = version
Packit Service 21c75c
        self.description, self.issues, self.epilog = [], [], []
Packit Service 21c75c
        return previous_version
Packit Service 21c75c
Packit Service 21c75c
    def _parse_issue(self, line):
Packit Service 21c75c
        """Parse an issue number from a line.
Packit Service 21c75c
Packit Service 21c75c
        It changes the state of the parser.
Packit Service 21c75c
Packit Service 21c75c
        :param line: the line to be parsed
Packit Service 21c75c
        :type line: str
Packit Service 21c75c
        :returns: returns :data:`True` if the line refers to an issue,
Packit Service 21c75c
           otherwise it returns :data:`False`
Packit Service 21c75c
        :rtype: bool
Packit Service 21c75c
Packit Service 21c75c
        """
Packit Service 21c75c
        match = re.match(r'^\* :rhbug:`(\d+)`\n$', line)
Packit Service 21c75c
        if not match:
Packit Service 21c75c
            return False
Packit Service 21c75c
        self.issues.append(match.group(1))
Packit Service 21c75c
        return True
Packit Service 21c75c
Packit Service 21c75c
    def _parse_line(self, line):
Packit Service 21c75c
        """Parse a line of DNF release notes.
Packit Service 21c75c
Packit Service 21c75c
        It changes the state of the parser.
Packit Service 21c75c
Packit Service 21c75c
        :param line: the line to be parsed
Packit Service 21c75c
        :type line: str
Packit Service 21c75c
        :returns: the version, the description, the list of issue
Packit Service 21c75c
           numbers and the epilog of the previous release
Packit Service 21c75c
        :rtype: tuple[str | None, str, list[str], str] | None
Packit Service 21c75c
Packit Service 21c75c
        """
Packit Service 21c75c
        needtitle = self._needline and self._version
Packit Service 21c75c
        if not needtitle and self._parse_overline(line):
Packit Service 21c75c
            return None
Packit Service 21c75c
        if self._needline and not self._version and self._parse_title(line):
Packit Service 21c75c
            return None
Packit Service 21c75c
        if self._needline and self._version:
Packit Service 21c75c
            previous_version = self._parse_underline(line)
Packit Service 21c75c
            if previous_version:
Packit Service 21c75c
                return previous_version
Packit Service 21c75c
        if not self.epilog and self._parse_issue(line):
Packit Service 21c75c
            return None
Packit Service 21c75c
        if not self.issues:
Packit Service 21c75c
            self.description.append(line)
Packit Service 21c75c
            return None
Packit Service 21c75c
        self.epilog.append(line)
Packit Service 21c75c
Packit Service 21c75c
    def parse_lines(self, lines):
Packit Service 21c75c
        """Parse the lines of DNF release notes.
Packit Service 21c75c
Packit Service 21c75c
        :param lines: the line to be parsed
Packit Service 21c75c
        :type lines: collections.Iterable[str]
Packit Service 21c75c
        :returns: a generator yielding the version, the description, the
Packit Service 21c75c
           list of issue numbers and the epilog of each release version
Packit Service 21c75c
        :rtype: generator[tuple[str | None, str, list[str], str]]
Packit Service 21c75c
Packit Service 21c75c
        """
Packit Service 21c75c
        self._needline = None
Packit Service 21c75c
        self._version = None
Packit Service 21c75c
        self.version = None
Packit Service 21c75c
        self.description = []
Packit Service 21c75c
        self.issues = []
Packit Service 21c75c
        self.epilog = []
Packit Service 21c75c
        for line in lines:
Packit Service 21c75c
            previous_version = self._parse_line(line)
Packit Service 21c75c
            if previous_version:
Packit Service 21c75c
                yield previous_version
Packit Service 21c75c
        yield self._last_version
Packit Service 21c75c
Packit Service 21c75c
Packit Service 21c75c
class TestCase(unittest.TestCase):
Packit Service 21c75c
Packit Service 21c75c
    """A test fixture common to all tests.
Packit Service 21c75c
Packit Service 21c75c
    Among other things, the fixture contains a non-bare DNF repository
Packit Service 21c75c
    with a spec file specifying an unreleased version, a tag dnf-1.0.1-1
Packit Service 21c75c
    matching the version 1.0.1, one extra commit which resolves an issue
Packit Service 21c75c
    and release notes matching the revision 9110490 of DNF.
Packit Service 21c75c
Packit Service 21c75c
    :cvar VERSION: the unreleased version specified in the spec file
Packit Service 21c75c
    :type VERSION: str
Packit Service 21c75c
    :cvar ISSUE: the number of the issue resolved by the extra commit
Packit Service 21c75c
    :type ISSUE: str
Packit Service 21c75c
    :ivar repository: the testing repository
Packit Service 21c75c
    :type repository: git.Repo
Packit Service 21c75c
    :ivar commit: the extra commit
Packit Service 21c75c
    :type commit: unicode
Packit Service 21c75c
Packit Service 21c75c
    """
Packit Service 21c75c
Packit Service 21c75c
    VERSION = '999.9.9'
Packit Service 21c75c
Packit Service 21c75c
    ISSUE = '123456'
Packit Service 21c75c
Packit Service 21c75c
    def setUp(self):
Packit Service 21c75c
        """Prepare the test fixture.
Packit Service 21c75c
Packit Service 21c75c
        :const:`__file__` is needed to prepare the fixture.
Packit Service 21c75c
Packit Service 21c75c
        """
Packit Service 21c75c
        dirname = tempfile.mkdtemp()
Packit Service 21c75c
        self.addCleanup(shutil.rmtree, dirname)
Packit Service 21c75c
        self.repository = detect_repository().clone(dirname)
Packit Service 21c75c
        self.repository.head.reset(
Packit Service 21c75c
            '9110490d690bbad10977b86e7ffbe1feeae26e03', working_tree=True)
Packit Service 21c75c
        with open(os.path.join(dirname, SPEC_FN), 'wt') as specfile:
Packit Service 21c75c
            specfile.write(
Packit Service 21c75c
                'Name: dnf\n' +
Packit Service 21c75c
                'Version: {}\n'.format(self.VERSION) +
Packit Service 21c75c
                'Release: 1\n'
Packit Service 21c75c
                'Summary: Package manager forked from Yum\n'
Packit Service 21c75c
                'License: GPLv2+ and GPLv2 and GPL\n'
Packit Service 21c75c
                '%description\n'
Packit Service 21c75c
                'Package manager forked from Yum, using libsolv.\n'
Packit Service 21c75c
                '%files\n')
Packit Service 21c75c
        self.repository.index.add([SPEC_FN])
Packit Service 21c75c
        self.commit = self.repository.index.commit(
Packit Service 21c75c
            u'Version (RhBug:{})'.format(self.ISSUE.decode()))
Packit Service 21c75c
Packit Service 21c75c
    @staticmethod
Packit Service 21c75c
    @contextlib.contextmanager
Packit Service 21c75c
    def _read_copy(name):
Packit Service 21c75c
        """Create and open a readable copy of a file.
Packit Service 21c75c
Packit Service 21c75c
        :param name: name of the file
Packit Service 21c75c
        :type name: str
Packit Service 21c75c
        :returns: the readable copy
Packit Service 21c75c
        :rtype: file
Packit Service 21c75c
        :raises exceptions.IOError: if the file cannot be opened
Packit Service 21c75c
Packit Service 21c75c
        """
Packit Service 21c75c
        with tempfile.TemporaryFile('wt+') as copy:
Packit Service 21c75c
            with open(name, 'rt') as original:
Packit Service 21c75c
                shutil.copyfileobj(original, copy)
Packit Service 21c75c
            copy.seek(0)
Packit Service 21c75c
            yield copy
Packit Service 21c75c
Packit Service 21c75c
    @contextlib.contextmanager
Packit Service 21c75c
    def _patch_file(self):
Packit Service 21c75c
        """Temporarily set :const:`__file__` to point to the testing repo.
Packit Service 21c75c
Packit Service 21c75c
        :returns: a context manager
Packit Service 21c75c
        :rtype: contextmanager
Packit Service 21c75c
Packit Service 21c75c
        """
Packit Service 21c75c
        filename = os.path.join(
Packit Service 21c75c
            self.repository.working_dir, 'scripts', 'update_releasenotes.py')
Packit Service 21c75c
        original = __file__
Packit Service 21c75c
        with tests.mock.patch('update_releasenotes.__file__', filename):
Packit Service 21c75c
            assert __file__ != original, 'double check that the patch works'
Packit Service 21c75c
            yield
Packit Service 21c75c
Packit Service 21c75c
    @contextlib.contextmanager
Packit Service 21c75c
    def _assert_logs(self, level, regex):
Packit Service 21c75c
        """Test whether a message matching an expression is logged.
Packit Service 21c75c
Packit Service 21c75c
        :param level: the level of the message
Packit Service 21c75c
        :type level: int
Packit Service 21c75c
        :param regex: the regular expression to be matched
Packit Service 21c75c
        :type regex: re.RegexObject
Packit Service 21c75c
        :returns: a context manager which represents the block in which
Packit Service 21c75c
           the message should be logged
Packit Service 21c75c
        :rtype: contextmanager
Packit Service 21c75c
        :raises exceptions.AssertionError: if the test fails
Packit Service 21c75c
Packit Service 21c75c
        """
Packit Service 21c75c
        class Handler(logging.Handler):
Packit Service 21c75c
            def __init__(self, regex):
Packit Service 21c75c
                super(Handler, self).__init__()
Packit Service 21c75c
                self.regex = regex
Packit Service 21c75c
                self.found = False
Packit Service 21c75c
Packit Service 21c75c
            def emit(self, record):
Packit Service 21c75c
                if not self.found:
Packit Service 21c75c
                    self.found = self.regex.match(record.getMessage())
Packit Service 21c75c
        handler = Handler(regex)
Packit Service 21c75c
        LOGGER.setLevel(level)
Packit Service 21c75c
        LOGGER.addHandler(handler)
Packit Service 21c75c
        yield
Packit Service 21c75c
        self.assertTrue(handler.found)
Packit Service 21c75c
Packit Service 21c75c
    @contextlib.contextmanager
Packit Service 21c75c
    def _assert_prints(self, regex, stream):
Packit Service 21c75c
        """Test whether a message matching an expression is printed.
Packit Service 21c75c
Packit Service 21c75c
        :param regex: the regular expression to be matched
Packit Service 21c75c
        :type regex: re.RegexObject
Packit Service 21c75c
        :param stream: a name of the stream to be matched
Packit Service 21c75c
        :type stream: str
Packit Service 21c75c
        :returns: a context manager which represents the block in which
Packit Service 21c75c
           the message should be printed
Packit Service 21c75c
        :rtype: contextmanager
Packit Service 21c75c
        :raises exceptions.AssertionError: if the test fails
Packit Service 21c75c
Packit Service 21c75c
        """
Packit Service 21c75c
        with tests.mock.patch(stream, io.BytesIO()) as mock:
Packit Service 21c75c
            yield
Packit Service 21c75c
            self.assertRegexpMatches(mock.getvalue(), regex)
Packit Service 21c75c
Packit Service 21c75c
    def _assert_iter_equal(self, actual, expected):
Packit Service 21c75c
        """Test whether two iterables are equal.
Packit Service 21c75c
Packit Service 21c75c
        :param actual: one of the iterables
Packit Service 21c75c
        :type actual: collections.Iterable[object]
Packit Service 21c75c
        :param expected: the other iterable
Packit Service 21c75c
        :type expected: collections.Iterable[object]
Packit Service 21c75c
        :raises exceptions.AssertionError: if the test fails
Packit Service 21c75c
Packit Service 21c75c
        """
Packit Service 21c75c
        self.assertTrue(all(
Packit Service 21c75c
            actual_ == expected_ for actual_, expected_ in
Packit Service 21c75c
            itertools.izip_longest(actual, expected, fillvalue=object())))
Packit Service 21c75c
Packit Service 21c75c
    def test_detect_repository(self):
Packit Service 21c75c
        """Test whether correct repository is detected.
Packit Service 21c75c
Packit Service 21c75c
        :raises exceptions.AssertionError: if the test fails
Packit Service 21c75c
Packit Service 21c75c
        """
Packit Service 21c75c
        with self._patch_file():
Packit Service 21c75c
            self.assertEqual(
Packit Service 21c75c
                detect_repository().working_dir, self.repository.working_dir)
Packit Service 21c75c
Packit Service 21c75c
    def test_detect_version(self):
Packit Service 21c75c
        """Test whether correct version is detected.
Packit Service 21c75c
Packit Service 21c75c
        :raises exceptions.AssertionError: if the test fails
Packit Service 21c75c
Packit Service 21c75c
        """
Packit Service 21c75c
        self.assertEqual(detect_version(self.repository), self.VERSION)
Packit Service 21c75c
Packit Service 21c75c
    def test_find_tag_name(self):
Packit Service 21c75c
        """Test whether correct tag is detected.
Packit Service 21c75c
Packit Service 21c75c
        :raises exceptions.AssertionError: if the test fails
Packit Service 21c75c
Packit Service 21c75c
        """
Packit Service 21c75c
        self.assertEqual(find_tag(self.repository, '1.0.1'), 'dnf-1.0.1-1')
Packit Service 21c75c
Packit Service 21c75c
    def test_find_tag_none(self):
Packit Service 21c75c
        """Test whether correct tag is detected.
Packit Service 21c75c
Packit Service 21c75c
        :raises exceptions.AssertionError: if the test fails
Packit Service 21c75c
Packit Service 21c75c
        """
Packit Service 21c75c
        self.assertIsNone(find_tag(self.repository, '9999'))
Packit Service 21c75c
Packit Service 21c75c
    def test_iter_unreleased_commits(self):
Packit Service 21c75c
        """Test whether correct commits are yielded.
Packit Service 21c75c
Packit Service 21c75c
        :raises exceptions.AssertionError: if the test fails
Packit Service 21c75c
Packit Service 21c75c
        """
Packit Service 21c75c
        commits = iter_unreleased_commits(self.repository)
Packit Service 21c75c
        self.assertItemsEqual(
Packit Service 21c75c
            (commit.hexsha for commit in commits), [self.commit.hexsha])
Packit Service 21c75c
Packit Service 21c75c
    def test_parse_issues(self):
Packit Service 21c75c
        """Test whether correct issues are yielded.
Packit Service 21c75c
Packit Service 21c75c
        :raises exceptions.AssertionError: if the test fails
Packit Service 21c75c
Packit Service 21c75c
        """
Packit Service 21c75c
        self.assertItemsEqual(parse_issues([self.commit]), [self.ISSUE])
Packit Service 21c75c
Packit Service 21c75c
    def test_extend_releases_extend(self):
Packit Service 21c75c
        """Test whether the release version is extended.
Packit Service 21c75c
Packit Service 21c75c
        :raises exceptions.AssertionError: if the test fails
Packit Service 21c75c
Packit Service 21c75c
        """
Packit Service 21c75c
        releases = [
Packit Service 21c75c
            (None, 'd1\n', [], ''),
Packit Service 21c75c
            ('1.0.1', '\nd2\n', ['234567'], '\n'),
Packit Service 21c75c
            ('999.9.9', '\nd3\n', ['345678'], '\n')]
Packit Service 21c75c
        expected = [
Packit Service 21c75c
            (None, 'd1\n', [], ''),
Packit Service 21c75c
            ('1.0.1', '\nd2\n', ['456789', '234567'], '\n'),
Packit Service 21c75c
            ('999.9.9', '\nd3\n', ['345678'], '\n')]
Packit Service 21c75c
        self.assertItemsEqual(
Packit Service 21c75c
            extend_releases(releases, '1.0.1', ['456789']), expected)
Packit Service 21c75c
Packit Service 21c75c
    def test_extend_releases_skip(self):
Packit Service 21c75c
        """Test whether the already present issues are skipped.
Packit Service 21c75c
Packit Service 21c75c
        :raises exceptions.AssertionError: if the test fails
Packit Service 21c75c
Packit Service 21c75c
        """
Packit Service 21c75c
        releases = [
Packit Service 21c75c
            (None, 'd1\n', [], ''),
Packit Service 21c75c
            ('1.0.1', '\nd2\n', ['234567'], '\n'),
Packit Service 21c75c
            ('999.9.9', '\nd3\n', ['345678'], '\n')]
Packit Service 21c75c
        expected = [
Packit Service 21c75c
            (None, 'd1\n', [], ''),
Packit Service 21c75c
            ('1.0.1', '\nd2\n', ['234567'], '\n'),
Packit Service 21c75c
            ('999.9.9', '\nd3\n', ['345678'], '\n')]
Packit Service 21c75c
        self.assertItemsEqual(
Packit Service 21c75c
            extend_releases(releases, '1.0.1', ['234567']), expected)
Packit Service 21c75c
Packit Service 21c75c
    def test_extend_releases_append(self):
Packit Service 21c75c
        """Test whether the rel. version is appended to the beginning.
Packit Service 21c75c
Packit Service 21c75c
        :raises exceptions.AssertionError: if the test fails
Packit Service 21c75c
Packit Service 21c75c
        """
Packit Service 21c75c
        releases = [
Packit Service 21c75c
            (None, 'd1\n', [], ''),
Packit Service 21c75c
            ('1.0.1', '\nd2\n', ['234567'], '\n')]
Packit Service 21c75c
        expected = [
Packit Service 21c75c
            (None, 'd1\n', [], ''),
Packit Service 21c75c
            ('999.9.9', '\n', ['345678'], '\n'),
Packit Service 21c75c
            ('1.0.1', '\nd2\n', ['234567'], '\n')]
Packit Service 21c75c
        self.assertItemsEqual(
Packit Service 21c75c
            extend_releases(releases, '999.9.9', ['345678']), expected)
Packit Service 21c75c
Packit Service 21c75c
    def test_format_release_version(self):
Packit Service 21c75c
        """Test whether correct string is returned.
Packit Service 21c75c
Packit Service 21c75c
        :raises exceptions.AssertionError: if the test fails
Packit Service 21c75c
Packit Service 21c75c
        """
Packit Service 21c75c
        self.assertEqual(
Packit Service 21c75c
            format_release('1.0.1', '\ndesc\n', ['123456', '234567'], '\ne\n'),
Packit Service 21c75c
            '===================\n'
Packit Service 21c75c
            '1.0.1 Release Notes\n'
Packit Service 21c75c
            '===================\n'
Packit Service 21c75c
            '\n'
Packit Service 21c75c
            'desc\n'
Packit Service 21c75c
            '* :rhbug:`123456`\n'
Packit Service 21c75c
            '* :rhbug:`234567`\n'
Packit Service 21c75c
            '\n'
Packit Service 21c75c
            'e\n')
Packit Service 21c75c
Packit Service 21c75c
    def test_format_release_none(self):
Packit Service 21c75c
        """Test whether no version is handled properly.
Packit Service 21c75c
Packit Service 21c75c
        :raises exceptions.AssertionError: if the test fails
Packit Service 21c75c
Packit Service 21c75c
        """
Packit Service 21c75c
        self.assertEqual(format_release(None, 'l1\nl2\n', [], ''), 'l1\nl2\n')
Packit Service 21c75c
Packit Service 21c75c
    def test_update_notes_append(self):
Packit Service 21c75c
        """Test whether the rel. version is appended to the beginning.
Packit Service 21c75c
Packit Service 21c75c
        :raises exceptions.AssertionError: if the test fails
Packit Service 21c75c
Packit Service 21c75c
        """
Packit Service 21c75c
        regex = re.compile(
Packit Service 21c75c
            '^Update finished. See the diff to the Git index:\n.+')
Packit Service 21c75c
        notesfn = os.path.join(self.repository.working_dir, NOTES_FN)
Packit Service 21c75c
        title = TITLE_PAT.format(version=self.VERSION)
Packit Service 21c75c
        extra = [
Packit Service 21c75c
            '\n',
Packit Service 21c75c
            '{}\n'.format('=' * (len(title) - 1)),
Packit Service 21c75c
            title,
Packit Service 21c75c
            '{}\n'.format('=' * (len(title) - 1)),
Packit Service 21c75c
            '\n',
Packit Service 21c75c
            ISSUE_PAT.format(number=self.ISSUE)]
Packit Service 21c75c
        with self._read_copy(notesfn) as original:
Packit Service 21c75c
            # Insert the extra lines right after the 22nd line.
Packit Service 21c75c
            expected = itertools.chain(
Packit Service 21c75c
                itertools.islice(original, 0, 22), extra, original)
Packit Service 21c75c
            with self._patch_file(), self._assert_logs(logging.INFO, regex):
Packit Service 21c75c
                update_notes()
Packit Service 21c75c
            with open(notesfn, 'rt') as actual:
Packit Service 21c75c
                self._assert_iter_equal(actual, expected)
Packit Service 21c75c
Packit Service 21c75c
    def test_update_notes_released(self):
Packit Service 21c75c
        """Test whether the released version is detected.
Packit Service 21c75c
Packit Service 21c75c
        :raises exceptions.AssertionError: if the test fails
Packit Service 21c75c
Packit Service 21c75c
        """
Packit Service 21c75c
        self.repository.create_tag(TAG_PAT.format(version=self.VERSION))
Packit Service 21c75c
        with self._patch_file():
Packit Service 21c75c
            self.assertRaises(ValueError, update_notes)
Packit Service 21c75c
Packit Service 21c75c
    def test_main_append(self):
Packit Service 21c75c
        """Test whether the release version is appended to the end.
Packit Service 21c75c
Packit Service 21c75c
        :raises exceptions.AssertionError: if the test fails
Packit Service 21c75c
Packit Service 21c75c
        """
Packit Service 21c75c
        regex = re.compile(
Packit Service 21c75c
            '^INFO Update finished. See the diff to the Git index:\n.+', re.M)
Packit Service 21c75c
        notesfn = os.path.join(self.repository.working_dir, NOTES_FN)
Packit Service 21c75c
        title = TITLE_PAT.format(version=self.VERSION)
Packit Service 21c75c
        extra = [
Packit Service 21c75c
            '\n',
Packit Service 21c75c
            '{}\n'.format('=' * (len(title) - 1)),
Packit Service 21c75c
            title,
Packit Service 21c75c
            '{}\n'.format('=' * (len(title) - 1)),
Packit Service 21c75c
            '\n',
Packit Service 21c75c
            ISSUE_PAT.format(number=self.ISSUE)]
Packit Service 21c75c
        with self._read_copy(notesfn) as original:
Packit Service 21c75c
            # Insert the extra lines right after the 22nd line.
Packit Service 21c75c
            expected = itertools.chain(
Packit Service 21c75c
                itertools.islice(original, 0, 22), extra, original)
Packit Service 21c75c
            with \
Packit Service 21c75c
                    tests.mock.patch('sys.argv', ['prog']), \
Packit Service 21c75c
                    self._patch_file(), \
Packit Service 21c75c
                    self._assert_prints(regex, 'sys.stderr'):
Packit Service 21c75c
                main()
Packit Service 21c75c
            with open(notesfn, 'rt') as actual:
Packit Service 21c75c
                self._assert_iter_equal(actual, expected)
Packit Service 21c75c
Packit Service 21c75c
    def test_main_released(self):
Packit Service 21c75c
        """Test whether the released version is detected.
Packit Service 21c75c
Packit Service 21c75c
        :raises exceptions.AssertionError: if the test fails
Packit Service 21c75c
Packit Service 21c75c
        """
Packit Service 21c75c
        self.repository.create_tag(TAG_PAT.format(version=self.VERSION))
Packit Service 21c75c
        with \
Packit Service 21c75c
                tests.mock.patch('sys.argv', ['prog']), self._patch_file(), \
Packit Service 21c75c
                self.assertRaises(SystemExit) as context:
Packit Service 21c75c
            main()
Packit Service 21c75c
        self.assertNotEqual(context.exception.code, 0)
Packit Service 21c75c
Packit Service 21c75c
    def test_releasenotesparser(self):
Packit Service 21c75c
        """Test whether correct release notes are yielded.
Packit Service 21c75c
Packit Service 21c75c
        :raises exceptions.AssertionError: if the test fails
Packit Service 21c75c
Packit Service 21c75c
        """
Packit Service 21c75c
        notesfn = os.path.join(self.repository.working_dir, NOTES_FN)
Packit Service 21c75c
        parser = ReleaseNotesParser()
Packit Service 21c75c
        descriptions = [
Packit Service 21c75c
            # None
Packit Service 21c75c
            '..\n'
Packit Service 21c75c
            '  Copyright (C) 2014  Red Hat, Inc.\n'
Packit Service 21c75c
            '\n'
Packit Service 21c75c
            '  This copyrighted material is made available to anyone wishing '
Packit Service 21c75c
            'to use,\n  modify, copy, or redistribute it subject to the terms '
Packit Service 21c75c
            'and conditions of\n  the GNU General Public License v.2, or (at '
Packit Service 21c75c
            'your option) any later version.\n  This program is distributed in'
Packit Service 21c75c
            ' the hope that it will be useful, but WITHOUT\n  ANY WARRANTY '
Packit Service 21c75c
            'expressed or implied, including the implied warranties of\n  '
Packit Service 21c75c
            'MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU'
Packit Service 21c75c
            ' General\n  Public License for more details.  You should have '
Packit Service 21c75c
            'received a copy of the\n  GNU General Public License along with '
Packit Service 21c75c
            'this program; if not, write to the\n  Free Software Foundation, '
Packit Service 21c75c
            'Inc., 51 Franklin Street, Fifth Floor, Boston, MA\n  02110-1301, '
Packit Service 21c75c
            'USA.  Any Red Hat trademarks that are incorporated in the\n  '
Packit Service 21c75c
            'source code or documentation are not subject to the GNU General '
Packit Service 21c75c
            'Public\n  License and may only be used or replicated with the '
Packit Service 21c75c
            'express permission of\n  Red Hat, Inc.\n'
Packit Service 21c75c
            '\n'
Packit Service 21c75c
            '###################\n'
Packit Service 21c75c
            ' DNF Release Notes\n'
Packit Service 21c75c
            '###################\n'
Packit Service 21c75c
            '\n'
Packit Service 21c75c
            '.. contents::\n'
Packit Service 21c75c
            '\n',
Packit Service 21c75c
            # 0.3.1
Packit Service 21c75c
            '\n0.3.1 brings mainly changes to the automatic metadata '
Packit Service 21c75c
            'synchronization. In\nFedora, ``dnf makecache`` is triggered via '
Packit Service 21c75c
            'SystemD timers now and takes an\noptional ``background`` '
Packit Service 21c75c
            'extra-argument to run in resource-considerate mode (no\nsyncing '
Packit Service 21c75c
            'when running on laptop battery, only actually performing the '
Packit Service 21c75c
            'check at\nmost once every three hours). Also, the IO and CPU '
Packit Service 21c75c
            'priorities of the\ntimer-triggered process are lowered now and '
Packit Service 21c75c
            "shouldn't as noticeably impact the\nsystem's performance.\n\nThe "
Packit Service 21c75c
            'administrator can also easily disable the automatic metadata '
Packit Service 21c75c
            'updates by\nsetting :ref:`metadata_timer_sync '
Packit Service 21c75c
            '<metadata_timer_sync-label>` to 0.\n\nThe default value of '
Packit Service 21c75c
            ':ref:`metadata_expire <metadata_expire-label>` was\nincreased '
Packit Service 21c75c
            'from 6 hours to 48 hours. In Fedora, the repos usually set this\n'
Packit Service 21c75c
            'explicitly so this change is not going to cause much impact.\n\n'
Packit Service 21c75c
            'The following reported issues are fixed in this release:\n\n',
Packit Service 21c75c
            # 0.3.2
Packit Service 21c75c
            '\nThe major improvement in this version is in speeding up syncing'
Packit Service 21c75c
            ' of repositories\nusing metalink by looking at the repomd.xml '
Packit Service 21c75c
            'checksums. This effectively lets DNF\ncheaply refresh expired '
Packit Service 21c75c
            'repositories in cases where the original has not\nchanged\\: for '
Packit Service 21c75c
            'instance the main Fedora repository is refreshed with one 30 kB\n'
Packit Service 21c75c
            'HTTP download. This functionality is present in the current Yum '
Packit Service 21c75c
            "but hasn't\nworked in DNF since 3.0.0.\n\nOtherwise this is "
Packit Service 21c75c
            'mainly a release fixing bugs and tracebacks. The following\n'
Packit Service 21c75c
            'reported bugs are fixed:\n\n',
Packit Service 21c75c
            # 0.3.3
Packit Service 21c75c
            '\nThe improvements in 0.3.3 are only API changes to the logging. '
Packit Service 21c75c
            'There is a new\nmodule ``dnf.logging`` that defines simplified '
Packit Service 21c75c
            'logging structure compared to\nYum, with fewer logging levels and'
Packit Service 21c75c
            ' `simpler usage for the developers\n
Packit Service 21c75c
            'rpm-software-management/dnf/wiki/Hacking#logging>`_. The RPM '
Packit Service 21c75c
            'transaction logs are\nno longer in ``/var/log/dnf.transaction.log'
Packit Service 21c75c
            '`` but in ``/var/log/dnf.rpm.log`` by\ndefault.\n\nThe exception '
Packit Service 21c75c
            'classes were simplified and moved to ``dnf.exceptions``.\n\nThe '
Packit Service 21c75c
            'following bugs are fixed in 0.3.3:\n\n',
Packit Service 21c75c
            # 0.3.4
Packit Service 21c75c
            '\n0.3.4 is the first DNF version since the fork from Yum that is '
Packit Service 21c75c
            'able to\nmanipulate the comps data. In practice, ``dnf group '
Packit Service 21c75c
            'install <group name>`` works\nagain. No other group commands are '
Packit Service 21c75c
            'supported yet.\n\nSupport for ``librepo-0.0.4`` and related '
Packit Service 21c75c
            'cleanups and extensions this new\nversion allows are included '
Packit Service 21c75c
            '(see the buglist below)\n\nThis version has also improved '
Packit Service 21c75c
            'reporting of obsoleted packages in the CLI (the\nYum-style '
Packit Service 21c75c
            '"replacing <package-nevra>" appears in the textual transaction\n'
Packit Service 21c75c
            'overview).\n\nThe following bugfixes are included in 0.3.4:\n\n',
Packit Service 21c75c
            # 0.3.5
Packit Service 21c75c
            '\nBesides few fixed bugs this version should not present any '
Packit Service 21c75c
            'differences for the\nuser. On the inside, the transaction '
Packit Service 21c75c
            'managing mechanisms have changed\ndrastically, bringing code '
Packit Service 21c75c
            'simplification, better maintainability and better\ntestability.\n'
Packit Service 21c75c
            '\nIn Fedora, there is a change in the spec file effectively '
Packit Service 21c75c
            'preventing the\nmakecache timer from running *immediately after '
Packit Service 21c75c
            'installation*. The timer\nservice is still enabled by default, '
Packit Service 21c75c
            'but unless the user starts it manually with\n``systemctl start '
Packit Service 21c75c
            'dnf-makecache.timer`` it will not run until after the first\n'
Packit Service 21c75c
            'reboot. This is in alignment with Fedora packaging best '
Packit Service 21c75c
            'practices.\n\nThe following bugfixes are included in 0.3.5:\n\n',
Packit Service 21c75c
            # 0.3.6
Packit Service 21c75c
            '\nThis is a bugfix release, including the following fixes:\n\n',
Packit Service 21c75c
            # 0.3.7
Packit Service 21c75c
            '\nThis is a bugfix release:\n\n',
Packit Service 21c75c
            # 0.3.8
Packit Service 21c75c
            '\nA new locking module has been integrated in this version, '
Packit Service 21c75c
            'clients should see the\nmessage about DNF lock being taken less '
Packit Service 21c75c
            'often.\n\nPanu Matilainen has submitted many patches to this '
Packit Service 21c75c
            'release to cleanup the RPM\ninterfacing modules.\n\nThe following'
Packit Service 21c75c
            ' bugs are fixed in this release:\n\n',
Packit Service 21c75c
            # 0.3.9
Packit Service 21c75c
            '\nThis is a quick bugfix release dealing with reported bugs and '
Packit Service 21c75c
            'tracebacks:\n\n',
Packit Service 21c75c
            # 0.3.10
Packit Service 21c75c
            '\nThe only major change is that ``skip_if_unavailable`` is '
Packit Service 21c75c
            ':ref:`enabled by\ndefault now <skip_if_unavailable_default>`.\n\n'
Packit Service 21c75c
            'A minor release otherwise, mainly to get a new version of DNF out'
Packit Service 21c75c
            ' that uses a\nfresh librepo. The following issues are now a thing'
Packit Service 21c75c
            ' of the past:\n\n',
Packit Service 21c75c
            # 0.3.11
Packit Service 21c75c
            '\nThe default multilib policy configuration value is ``best`` '
Packit Service 21c75c
            'now. This does not\npose any change for the Fedora users because '
Packit Service 21c75c
            'exactly the same default had been\npreviously achieved by a '
Packit Service 21c75c
            'setting in ``/etc/dnf/dnf.conf`` shipped with the\nFedora '
Packit Service 21c75c
            'package.\n\nAn important fix to the repo module speeds up package'
Packit Service 21c75c
            ' downloads again is present\nin this release. The full list of '
Packit Service 21c75c
            'fixes is:\n\n',
Packit Service 21c75c
            # 0.4.0
Packit Service 21c75c
            '\nThe new minor version brings many internal changes to the comps'
Packit Service 21c75c
            ' code, most comps\nparsing and processing is now delegated to '
Packit Service 21c75c
            '`libcomps\n<https://github.com/midnightercz/libcomps>`_ by '
Packit Service 21c75c
            'Jind\xc5\x99ich Lu\xc5\xbea.\n\nThe ``overwrite_groups`` config '
Packit Service 21c75c
            'option has been dropped in this version and DNF\nacts if it was '
Packit Service 21c75c
            '0, that is groups with the same name are merged together.\n\nThe '
Packit Service 21c75c
            'currently supported groups commands (``group list`` and '
Packit Service 21c75c
            '``group install``)\nare documented on the manpage now.\n\nThe '
Packit Service 21c75c
            '0.4.0 version is the first one supported by the DNF Payload for '
Packit Service 21c75c
            'Anaconda and\nmany changes since 0.3.11 make that possible by '
Packit Service 21c75c
            'cleaning up the API and making\nit more sane (cleanup of '
Packit Service 21c75c
            '``yumvars`` initialization API, unifying the RPM\ntransaction '
Packit Service 21c75c
            'callback objects hierarchy, slimming down ``dnf.rpmUtils.arch``,'
Packit Service 21c75c
            '\nimproved logging).\n\nFixes for the following are contained in '
Packit Service 21c75c
            'this version:\n\n',
Packit Service 21c75c
            # 0.4.1
Packit Service 21c75c
            '\nThe focus of this release was to support our efforts in '
Packit Service 21c75c
            'implementing the DNF\nPayload for Anaconda, with changes on the '
Packit Service 21c75c
            'API side of things (better logging,\nnew ``Base.reset()`` '
Packit Service 21c75c
            'method).\n\nSupport for some irrelevant config options has been '
Packit Service 21c75c
            'dropped (``kernelpkgnames``,\n``exactarch``, '
Packit Service 21c75c
            '``rpm_check_debug``). We also no longer detect metalinks in the\n'
Packit Service 21c75c
            '``mirrorlist`` option (see `Fedora bug 948788\n'
Packit Service 21c75c
            '<https://bugzilla.redhat.com/show_bug.cgi?id=948788>`_).\n\nDNF '
Packit Service 21c75c
            'is on its way to drop the urlgrabber dependency and the first set'
Packit Service 21c75c
            ' of patches\ntowards this goal is already in.\n\nExpect the '
Packit Service 21c75c
            'following bugs to go away with upgrade to 0.4.1:\n\n',
Packit Service 21c75c
            # 0.4.2
Packit Service 21c75c
            '\nDNF now downloads packages for the transaction in parallel with'
Packit Service 21c75c
            ' progress bars\nupdated to effectively represent this. Since so '
Packit Service 21c75c
            'many things in the downloading\ncode were changing, we figured it'
Packit Service 21c75c
            ' was a good idea to finally drop urlgrabber\ndependency at the '
Packit Service 21c75c
            "same time. Indeed, this is the first version that doesn't\n"
Packit Service 21c75c
            'require urlgrabber for neither build nor run.\n\nSimilarly, since'
Packit Service 21c75c
            ' `librepo started to support this\n
Packit Service 21c75c
            'librepo/commit/acf458f29f7234d2d8d93a68391334343beae4b9>`_,\n'
Packit Service 21c75c
            'downloads in DNF now use the fastests mirrors available by '
Packit Service 21c75c
            "default.\n\nThe option to :ref:`specify repositories' costs "
Packit Service 21c75c
            '<repo_cost-label>` has been\nreadded.\n\nInternally, DNF has seen'
Packit Service 21c75c
            ' first part of ongoing refactorings of the basic\noperations '
Packit Service 21c75c
            '(install, update) as well as a couple of new API methods '
Packit Service 21c75c
            'supporting\ndevelopment of extensions.\n\nThese bugzillas are '
Packit Service 21c75c
            'fixed in 0.4.2:\n\n',
Packit Service 21c75c
            # 0.4.3
Packit Service 21c75c
            '\nThis is an early release to get the latest DNF out with the '
Packit Service 21c75c
            'latest librepo\nfixing the `Too many open files\n'
Packit Service 21c75c
            '<https://bugzilla.redhat.com/show_bug.cgi?id=1015957>`_ bug.\n\n'
Packit Service 21c75c
            'In Fedora, the spec file has been updated to no longer depend on '
Packit Service 21c75c
            'precise\nversions of the libraries so in the future they can be '
Packit Service 21c75c
            'released\nindependently.\n\nThis release sees the finished '
Packit Service 21c75c
            'refactoring in error handling during basic\noperations and adds '
Packit Service 21c75c
            'support for ``group remove`` and ``group info`` commands,\ni.e. '
Packit Service 21c75c
            'the following two bugs:\n\n',
Packit Service 21c75c
            # 0.4.4
Packit Service 21c75c
            '\nThe initial support for Python 3 in DNF has been merged in this'
Packit Service 21c75c
            ' version. In\npractice one can not yet run the ``dnf`` command in'
Packit Service 21c75c
            ' Py3 but the unit tests\nalready pass there. We expect to give '
Packit Service 21c75c
            'Py3 and DNF heavy testing during the\nFedora 21 development cycle'
Packit Service 21c75c
            ' and eventually switch to it as the default. The plan\nis to drop'
Packit Service 21c75c
            ' Python 2 support as soon as Anaconda is running in Python 3.\n\n'
Packit Service 21c75c
            'Minor adjustments to allow Anaconda support also happened during '
Packit Service 21c75c
            'the last week,\nas well as a fix to a possibly severe bug that '
Packit Service 21c75c
            'one is however not really likely\nto see with non-devel Fedora '
Packit Service 21c75c
            'repos:\n\n',
Packit Service 21c75c
            # 0.4.5
Packit Service 21c75c
            '\nA serious bug causing `tracebacks during package downloads\n'
Packit Service 21c75c
            '<https://bugzilla.redhat.com/show_bug.cgi?id=1021087>`_ made it '
Packit Service 21c75c
            'into 0.4.4 and\nthis release contains a fix for that. Also, a '
Packit Service 21c75c
            'basic proxy support has been\nreadded now.\n\nBugs fixed in '
Packit Service 21c75c
            '0.4.5:\n\n',
Packit Service 21c75c
            # 0.4.6
Packit Service 21c75c
            '\n0.4.6 brings two new major features. Firstly, it is the revival'
Packit Service 21c75c
            ' of ``history\nundo``, so transactions can be reverted now.  '
Packit Service 21c75c
            'Secondly, DNF will now limit the\nnumber of installed kernels and'
Packit Service 21c75c
            ' *installonly* packages in general to the number\nspecified by '
Packit Service 21c75c
            ':ref:`installonly_limit <installonly-limit-label>` configuration'
Packit Service 21c75c
            '\noption.\n\nDNF now supports the ``group summary`` command and '
Packit Service 21c75c
            'one-word group commands no\nlonger cause tracebacks, e.g. '
Packit Service 21c75c
            '``dnf grouplist``.\n\nThere are vast internal changes to '
Packit Service 21c75c
            '``dnf.cli``, the subpackage that provides CLI\nto DNF. In '
Packit Service 21c75c
            'particular, it is now better separated from the core.\n\nThe '
Packit Service 21c75c
            'hawkey library used against DNF from with this versions uses a '
Packit Service 21c75c
            '`recent RPMDB\nloading optimization in libsolv\n'
Packit Service 21c75c
            '<https://github.com/openSUSE/libsolv/commit/843dc7e1>`_ that '
Packit Service 21c75c
            'shortens DNF\nstartup by seconds when the cached RPMDB is '
Packit Service 21c75c
            'invalid.\n\nWe have also added further fixes to support Python 3 '
Packit Service 21c75c
            "and enabled `librepo's\nfastestmirror caching optimization\n"
Packit Service 21c75c
            '
Packit Service 21c75c
            'b8a063763ccd8a84b8ec21a643461eaace9b9c08>`_\nto tighten the '
Packit Service 21c75c
            'download times even more.\n\nBugs fixed in 0.4.6:\n\n',
Packit Service 21c75c
            # 0.4.7
Packit Service 21c75c
            '\nWe start to publish the :doc:`api` with this release. It is '
Packit Service 21c75c
            'largely\nincomprehensive at the moment, yet outlines the shape of'
Packit Service 21c75c
            ' the documentation and\nthe process the project is going to use '
Packit Service 21c75c
            'to maintain it.\n\nThere are two Yum configuration options that '
Packit Service 21c75c
            'were dropped: :ref:`group_package_types '
Packit Service 21c75c
            '<group_package_types_dropped>` and '
Packit Service 21c75c
            ':ref:`upgrade_requirements_on_install '
Packit Service 21c75c
            '<upgrade_requirements_on_install_dropped>`.\n\nBugs fixed in '
Packit Service 21c75c
            '0.4.7:\n\n',
Packit Service 21c75c
            # 0.4.8
Packit Service 21c75c
            '\nThere are mainly internal changes, new API functions and '
Packit Service 21c75c
            'bugfixes in this release.\n\nPython 3 is fully supported now, the'
Packit Service 21c75c
            ' Fedora builds include the Py3 variant. The DNF program still '
Packit Service 21c75c
            'runs under Python 2.7 but the extension authors can now choose '
Packit Service 21c75c
            'what Python they prefer to use.\n\nThis is the first version of '
Packit Service 21c75c
            'DNF that deprecates some of its API. Clients using deprecated '
Packit Service 21c75c
            'code will see a message emitted to stderr using the standard '
Packit Service 21c75c
            '`Python warnings module '
Packit Service 21c75c
            '<http://docs.python.org/3.3/library/warnings.html>`_. You can '
Packit Service 21c75c
            'filter out :exc:`dnf.exceptions.DeprecationWarning` to suppress '
Packit Service 21c75c
            'them.\n\nAPI additions in 0.4.8:\n\n* :attr:`dnf.Base.sack`\n* '
Packit Service 21c75c
            ':attr:`dnf.conf.Conf.cachedir`\n* '
Packit Service 21c75c
            ':attr:`dnf.conf.Conf.config_file_path`\n* '
Packit Service 21c75c
            ':attr:`dnf.conf.Conf.persistdir`\n* :meth:`dnf.conf.Conf.read`\n*'
Packit Service 21c75c
            ' :class:`dnf.package.Package`\n* :class:`dnf.query.Query`\n* '
Packit Service 21c75c
            ':class:`dnf.subject.Subject`\n* :meth:`dnf.repo.Repo.__init__`\n*'
Packit Service 21c75c
            ' :class:`dnf.sack.Sack`\n* :class:`dnf.selector.Selector`\n* '
Packit Service 21c75c
            ':class:`dnf.transaction.Transaction`\n\nAPI deprecations in '
Packit Service 21c75c
            '0.4.8:\n\n* :mod:`dnf.queries` is deprecated now. If you need to '
Packit Service 21c75c
            'create instances of :class:`.Subject`, import it from '
Packit Service 21c75c
            ':mod:`dnf.subject`. To create :class:`.Query` instances it is '
Packit Service 21c75c
            'recommended to use :meth:`sack.query() <dnf.sack.Sack.query>`.\n'
Packit Service 21c75c
            '\nBugs fixed in 0.4.8:\n\n',
Packit Service 21c75c
            # 0.4.9
Packit Service 21c75c
            '\nSeveral Yum features are revived in this release. '
Packit Service 21c75c
            '``dnf history rollback`` now works again. The '
Packit Service 21c75c
            '``history userinstalled`` has been added, it displays a list of '
Packit Service 21c75c
            'ackages that the user manually selected for installation on an '
Packit Service 21c75c
            'installed system and does not include those packages that got '
Packit Service 21c75c
            "installed as dependencies.\n\nWe're happy to announce that the "
Packit Service 21c75c
            'API in 0.4.9 has been extended to finally support plugins. There '
Packit Service 21c75c
            'is a limited set of plugin hooks now, we will carefully add new '
Packit Service 21c75c
            'ones in the following releases. New marking operations have ben '
Packit Service 21c75c
            'added to the API and also some configuration options.\n\nAn '
Packit Service 21c75c
            'alternative to ``yum shell`` is provided now for its most common '
Packit Service 21c75c
            'use case: :ref:`replacing a non-leaf package with a conflicting '
Packit Service 21c75c
            'package <allowerasing_instead_of_shell>` is achieved by using the'
Packit Service 21c75c
            ' ``--allowerasing`` switch now.\n\nAPI additions in 0.4.9:\n\n* '
Packit Service 21c75c
            ':doc:`api_plugins`\n* :ref:`logging_label`\n* '
Packit Service 21c75c
            ':meth:`.Base.read_all_repos`\n* :meth:`.Base.reset`\n* '
Packit Service 21c75c
            ':meth:`.Base.downgrade`\n* :meth:`.Base.remove`\n* '
Packit Service 21c75c
            ':meth:`.Base.upgrade`\n* :meth:`.Base.upgrade_all`\n* '
Packit Service 21c75c
            ':attr:`.Conf.pluginpath`\n* :attr:`.Conf.reposdir`\n\nAPI '
Packit Service 21c75c
            'deprecations in 0.4.9:\n\n* :exc:`.PackageNotFoundError` is '
Packit Service 21c75c
            'deprecated for public use. Please catch :exc:`.MarkingError` '
Packit Service 21c75c
            'instead.\n* It is deprecated to use :meth:`.Base.install` return '
Packit Service 21c75c
            'value for anything. The method either returns or raises an '
Packit Service 21c75c
            'exception.\n\nBugs fixed in 0.4.9:\n\n',
Packit Service 21c75c
            # 0.4.10
Packit Service 21c75c
            '\n0.4.10 is a bugfix release that also adds some long-requested '
Packit Service 21c75c
            'CLI features and extends the plugin support with two new plugin '
Packit Service 21c75c
            'hooks. An important feature for plugin developers is going to be '
Packit Service 21c75c
            "the possibility to register plugin's own CLI command, available "
Packit Service 21c75c
            'from this version.\n\n``dnf history`` now recognizes ``last`` as '
Packit Service 21c75c
            'a special argument, just like other history commands.\n\n'
Packit Service 21c75c
            '``dnf install`` now accepts group specifications via the ``@`` '
Packit Service 21c75c
            'character.\n\nSupport for the ``--setopt`` option has been '
Packit Service 21c75c
            'readded from Yum.\n\nAPI additions in 0.4.10:\n\n* '
Packit Service 21c75c
            ':doc:`api_cli`\n* :attr:`.Plugin.name`\n* '
Packit Service 21c75c
            ':meth:`.Plugin.__init__` now specifies the second parameter as an'
Packit Service 21c75c
            ' instance of `.cli.Cli`\n* :meth:`.Plugin.sack`\n* '
Packit Service 21c75c
            ':meth:`.Plugin.transaction`\n* :func:`.repo.repo_id_invalid`\n\n'
Packit Service 21c75c
            'API changes in 0.4.10:\n\n* Plugin authors must specify '
Packit Service 21c75c
            ':attr:`.Plugin.name` when authoring a plugin.\n\nBugs fixed in '
Packit Service 21c75c
            '0.4.10:\n\n',
Packit Service 21c75c
            # 0.4.11
Packit Service 21c75c
            '\nThis is mostly a bugfix release following quickly after 0.4.10,'
Packit Service 21c75c
            ' with many updates to documentation.\n\nAPI additions in 0.4.11:'
Packit Service 21c75c
            '\n\n* :meth:`.Plugin.read_config`\n* :class:`.repo.Metadata`\n* '
Packit Service 21c75c
            ':attr:`.repo.Repo.metadata`\n\nAPI changes in 0.4.11:\n\n* '
Packit Service 21c75c
            ':attr:`.Conf.pluginpath` is no longer hard coded but depends on '
Packit Service 21c75c
            'the major Python version.\n\nBugs fixed in 0.4.11:\n\n',
Packit Service 21c75c
            # 0.4.12
Packit Service 21c75c
            '\nThis release disables fastestmirror by default as we received '
Packit Service 21c75c
            'many complains about it. There are also several bugfixes, most '
Packit Service 21c75c
            'importantly an issue has been fixed that caused packages '
Packit Service 21c75c
            'installed by Anaconda be removed together with a depending '
Packit Service 21c75c
            'package. It is now possible to use ``bandwidth`` and ``throttle``'
Packit Service 21c75c
            ' config values too.\n\nBugs fixed in 0.4.12:\n\n',
Packit Service 21c75c
            # 0.4.13
Packit Service 21c75c
            '\n0.4.13 finally ships support for `delta RPMS '
Packit Service 21c75c
            '<https://gitorious.org/deltarpm>`_. Enabling this can save some '
Packit Service 21c75c
            'bandwidth (and use some CPU time) when downloading packages for '
Packit Service 21c75c
            'updates.\n\nSupport for bash completion is also included in this '
Packit Service 21c75c
            'version. It is recommended to use the '
Packit Service 21c75c
            '``generate_completion_cache`` plugin to have the completion work '
Packit Service 21c75c
            'fast. This plugin will be also shipped with '
Packit Service 21c75c
            '``dnf-plugins-core-0.0.3``.\n\nThe '
Packit Service 21c75c
            ':ref:`keepcache <keepcache-label>` config option has been '
Packit Service 21c75c
            'readded.\n\nBugs fixed in 0.4.13:\n\n',
Packit Service 21c75c
            # 0.4.14
Packit Service 21c75c
            '\nThis quickly follows 0.4.13 to address the issue of crashes '
Packit Service 21c75c
            'when DNF output is piped into another program.\n\nAPI additions '
Packit Service 21c75c
            'in 0.4.14:\n\n* :attr:`.Repo.pkgdir`\n\nBugs fixed in 0.4.14:\n'
Packit Service 21c75c
            '\n',
Packit Service 21c75c
            # 0.4.15
Packit Service 21c75c
            '\nMassive refactoring of the downloads handling to provide better'
Packit Service 21c75c
            ' API for reporting download progress and fixed bugs are the main '
Packit Service 21c75c
            'things brought in 0.4.15.\n\nAPI additions in 0.4.15:\n\n* '
Packit Service 21c75c
            ':exc:`dnf.exceptions.DownloadError`\n* '
Packit Service 21c75c
            ':meth:`dnf.Base.download_packages` now takes the optional '
Packit Service 21c75c
            '`progress` parameter and can raise :exc:`.DownloadError`.\n* '
Packit Service 21c75c
            ':class:`dnf.callback.Payload`\n* '
Packit Service 21c75c
            ':class:`dnf.callback.DownloadProgress`\n* '
Packit Service 21c75c
            ':meth:`dnf.query.Query.filter` now also recognizes ``provides`` '
Packit Service 21c75c
            'as a filter name.\n\nBugs fixed in 0.4.15:\n\n',
Packit Service 21c75c
            # 0.4.16
Packit Service 21c75c
            '\nThe refactorings from 0.4.15 are introducing breakage causing '
Packit Service 21c75c
            'the background ``dnf makecache`` runs traceback. This release '
Packit Service 21c75c
            'fixes that.\n\nBugs fixed in 0.4.16:\n\n',
Packit Service 21c75c
            # 0.4.17
Packit Service 21c75c
            '\nThis release fixes many bugs in the downloads/DRPM CLI area. A '
Packit Service 21c75c
            'bug got fixed preventing a regular user from running read-only '
Packit Service 21c75c
            'operations using ``--cacheonly``. Another fix ensures that '
Packit Service 21c75c
            '``metadata_expire=never`` setting is respected. Lastly, the '
Packit Service 21c75c
            'release provides three requested API calls in the repo management'
Packit Service 21c75c
            ' area.\n\nAPI additions in 0.4.17:\n\n* '
Packit Service 21c75c
            ':meth:`dnf.repodict.RepoDict.all`\n* '
Packit Service 21c75c
            ':meth:`dnf.repodict.RepoDict.get_matching`\n* '
Packit Service 21c75c
            ':meth:`dnf.repo.Repo.set_progress_bar`\n\nBugs fixed in 0.4.17:\n'
Packit Service 21c75c
            '\n',
Packit Service 21c75c
            # 0.4.18
Packit Service 21c75c
            '\nSupport for ``dnf distro-sync <spec>`` finally arrives in this '
Packit Service 21c75c
            'version.\n\nDNF has moved to handling groups as objects,  tagged '
Packit Service 21c75c
            'installed/uninstalled independently from the actual installed '
Packit Service 21c75c
            'packages. This has been in Yum as the ``group_command=objects`` '
Packit Service 21c75c
            'setting and the default in recent Fedora releases. There are API '
Packit Service 21c75c
            'extensions related to this change as well as two new CLI '
Packit Service 21c75c
            'commands: ``group mark install`` and ``group mark remove``.\n\n'
Packit Service 21c75c
            'API items deprecated in 0.4.8 and 0.4.9 have been dropped in '
Packit Service 21c75c
            '0.4.18, in accordance with our :ref:`deprecating-label`.\n\nAPI '
Packit Service 21c75c
            'changes in 0.4.18:\n\n* :mod:`dnf.queries` has been dropped as '
Packit Service 21c75c
            'announced in `0.4.8 Release Notes`_\n* '
Packit Service 21c75c
            ':exc:`dnf.exceptions.PackageNotFoundError` has been dropped from '
Packit Service 21c75c
            'API as announced in `0.4.9 Release Notes`_\n* '
Packit Service 21c75c
            ':meth:`dnf.Base.install` no longer has to return the number of '
Packit Service 21c75c
            'marked packages as announced in `0.4.9 Release Notes`_\n\nAPI '
Packit Service 21c75c
            'deprecations in 0.4.18:\n\n* :meth:`dnf.Base.select_group` is '
Packit Service 21c75c
            'deprecated now. Please use :meth:`~.Base.group_install` instead.'
Packit Service 21c75c
            '\n\nAPI additions in 0.4.18:\n\n* :meth:`dnf.Base.group_install`'
Packit Service 21c75c
            '\n* :meth:`dnf.Base.group_remove`\n\nBugs fixed in 0.4.18:\n\n',
Packit Service 21c75c
            # 0.4.19
Packit Service 21c75c
            '\nArriving one week after 0.4.18, the 0.4.19 mainly provides a '
Packit Service 21c75c
            'fix to a traceback in group operations under non-root users.\n\n'
Packit Service 21c75c
            'DNF starts to ship separate translation files (.mo) starting with'
Packit Service 21c75c
            ' this release.\n\nBugs fixed in 0.4.19:\n\n',
Packit Service 21c75c
            # 0.5.0
Packit Service 21c75c
            '\nThe biggest improvement in 0.5.0 is complete support for groups'
Packit Service 21c75c
            ' `and environments '
Packit Service 21c75c
            '<https://bugzilla.redhat.com/show_bug.cgi?id=1063666>`_, '
Packit Service 21c75c
            'including internal database of installed groups independent of '
Packit Service 21c75c
            'the actual packages (concept known as groups-as-objects from '
Packit Service 21c75c
            'Yum). Upgrading groups is supported now with ``group upgrade`` '
Packit Service 21c75c
            'too.\n\nTo force refreshing of metadata before an operation (even'
Packit Service 21c75c
            ' if the data is not expired yet), `the refresh option has been '
Packit Service 21c75c
            'added <https://bugzilla.redhat.com/show_bug.cgi?id=1064226>`_.\n'
Packit Service 21c75c
            '\nInternally, the CLI went through several changes to allow for '
Packit Service 21c75c
            'better API accessibility like `granular requesting of root '
Packit Service 21c75c
            'permissions '
Packit Service 21c75c
            '<https://bugzilla.redhat.com/show_bug.cgi?id=1062889>`_.\n\nAPI '
Packit Service 21c75c
            'has got many more extensions, focusing on better manipulation '
Packit Service 21c75c
            'with comps and packages. There are new entries in '
Packit Service 21c75c
            ':doc:`cli_vs_yum` and :doc:`user_faq` too.\n\nSeveral resource '
Packit Service 21c75c
            'leaks (file descriptors, noncollectable Python objects) were '
Packit Service 21c75c
            'found and fixed.\n\nAPI changes in 0.5.0:\n\n* it is now '
Packit Service 21c75c
            'recommended that either :meth:`dnf.Base.close` is used, or that '
Packit Service 21c75c
            ':class:`dnf.Base` instances are treated as a context manager.\n\n'
Packit Service 21c75c
            'API extensions in 0.5.0:\n\n* :meth:`dnf.Base.add_remote_rpms`\n* '
Packit Service 21c75c
            ':meth:`dnf.Base.close`\n* :meth:`dnf.Base.group_upgrade`\n* '
Packit Service 21c75c
            ':meth:`dnf.Base.resolve` optionally accepts `allow_erasing` '
Packit Service 21c75c
            'arguments now.\n* :meth:`dnf.Base.package_downgrade`\n* '
Packit Service 21c75c
            ':meth:`dnf.Base.package_install`\n* '
Packit Service 21c75c
            ':meth:`dnf.Base.package_upgrade`\n* '
Packit Service 21c75c
            ':class:`dnf.cli.demand.DemandSheet`\n* '
Packit Service 21c75c
            ':attr:`dnf.cli.Command.base`\n* :attr:`dnf.cli.Command.cli`\n* '
Packit Service 21c75c
            ':attr:`dnf.cli.Command.summary`\n* :attr:`dnf.cli.Command.usage`'
Packit Service 21c75c
            '\n* :meth:`dnf.cli.Command.configure`\n* '
Packit Service 21c75c
            ':attr:`dnf.cli.Cli.demands`\n* :class:`dnf.comps.Package`\n* '
Packit Service 21c75c
            ':meth:`dnf.comps.Group.packages_iter`\n* '
Packit Service 21c75c
            ':data:`dnf.comps.MANDATORY` etc.\n\nBugs fixed in 0.5.0:\n\n',
Packit Service 21c75c
            # 0.5.1
Packit Service 21c75c
            '\nBugfix release with several internal cleanups. One outstanding '
Packit Service 21c75c
            'change for CLI users is that DNF is a lot less verbose now during'
Packit Service 21c75c
            ' the dependency resolving phase.\n\nBugs fixed in 0.5.1:\n\n',
Packit Service 21c75c
            # 0.5.2
Packit Service 21c75c
            '\nThis release brings `autoremove command '
Packit Service 21c75c
            '<https://bugzilla.redhat.com/show_bug.cgi?id=963345>`_ that '
Packit Service 21c75c
            'removes any package that was originally installed as a dependency'
Packit Service 21c75c
            ' (e.g. had not been specified as an explicit argument to the '
Packit Service 21c75c
            'install command) and is no longer needed.\n\nEnforced '
Packit Service 21c75c
            'verification of SSL connections can now be disabled with the '
Packit Service 21c75c
            ':ref:`sslverify setting <sslverify-label>`.\n\nWe have been '
Packit Service 21c75c
            'plagued with many crashes related to Unicode and encodings since '
Packit Service 21c75c
            "the 0.5.0 release. These have been cleared out now.\n\nThere's "
Packit Service 21c75c
            'more: improvement in startup time, `extended globbing semantics '
Packit Service 21c75c
            'for input arguments '
Packit Service 21c75c
            '<https://bugzilla.redhat.com/show_bug.cgi?id=1083679>`_ and '
Packit Service 21c75c
            '`better search relevance sorting '
Packit Service 21c75c
            '<https://bugzilla.redhat.com/show_bug.cgi?id=1093888>`_.\n\nBugs '
Packit Service 21c75c
            'fixed in 0.5.2:\n\n',
Packit Service 21c75c
            # 0.5.3
Packit Service 21c75c
            '\nA set of bugfixes related to i18n and Unicode handling. There '
Packit Service 21c75c
            'is a ``-4/-6`` switch and a corresponding :ref:`ip_resolve '
Packit Service 21c75c
            '<ip-resolve-label>` configuration option (both known from Yum) to'
Packit Service 21c75c
            ' force DNS resolving of hosts to IPv4 or IPv6 addresses.\n\n0.5.3'
Packit Service 21c75c
            ' comes with several extensions and clarifications in the API: '
Packit Service 21c75c
            'notably :class:`~.dnf.transaction.Transaction` is introspectible '
Packit Service 21c75c
            'now, :class:`Query.filter <dnf.query.Query.filter>` is more '
Packit Service 21c75c
            "useful with new types of arguments and we've hopefully shed more"
Packit Service 21c75c
            ' light on how a client is expected to setup the configuration '
Packit Service 21c75c
            ':attr:`~dnf.conf.Conf.substitutions`.\n\nFinally, plugin authors '
Packit Service 21c75c
            'can now use a new :meth:`~dnf.Plugin.resolved` hook.\n\nAPI '
Packit Service 21c75c
            'changes in 0.5.3:\n\n* extended description given for '
Packit Service 21c75c
            ':meth:`dnf.Base.fill_sack`\n* :meth:`dnf.Base.select_group` has '
Packit Service 21c75c
            'been dropped as announced in `0.4.18 Release Notes`_\n\nAPI '
Packit Service 21c75c
            'additions in 0.5.3:\n\n* :attr:`dnf.conf.Conf.substitutions`\n* '
Packit Service 21c75c
            ':attr:`dnf.package.Package.arch`\n* '
Packit Service 21c75c
            ':attr:`dnf.package.Package.buildtime`\n* '
Packit Service 21c75c
            ':attr:`dnf.package.Package.epoch`\n* '
Packit Service 21c75c
            ':attr:`dnf.package.Package.installtime`\n* '
Packit Service 21c75c
            ':attr:`dnf.package.Package.name`\n* '
Packit Service 21c75c
            ':attr:`dnf.package.Package.release`\n* '
Packit Service 21c75c
            ':attr:`dnf.package.Package.sourcerpm`\n* '
Packit Service 21c75c
            ':attr:`dnf.package.Package.version`\n* '
Packit Service 21c75c
            ':meth:`dnf.Plugin.resolved`\n* :meth:`dnf.query.Query.filter` '
Packit Service 21c75c
            'accepts suffixes for its argument keys now which change the '
Packit Service 21c75c
            'filter semantics.\n* :mod:`dnf.rpm`\n* '
Packit Service 21c75c
            ':class:`dnf.transaction.TransactionItem`\n* '
Packit Service 21c75c
            ':class:`dnf.transaction.Transaction` is iterable now.\n\nBugs '
Packit Service 21c75c
            'fixed in 0.5.3:\n\n',
Packit Service 21c75c
            # 0.5.4
Packit Service 21c75c
            '\nSeveral encodings bugs were fixed in this release, along with '
Packit Service 21c75c
            'some packaging issues and updates to :doc:`conf_ref`.\n\n'
Packit Service 21c75c
            'Repository :ref:`priority <repo_priority-label>` configuration '
Packit Service 21c75c
            'setting has been added, providing similar functionality to Yum '
Packit Service 21c75c
            "Utils' Priorities plugin.\n\nBugs fixed in 0.5.4:\n\n",
Packit Service 21c75c
            # 0.5.5
Packit Service 21c75c
            '\nThe full proxy configuration, API extensions and several '
Packit Service 21c75c
            'bugfixes are provided in this release.\n\nAPI changes in 0.5.5:\n'
Packit Service 21c75c
            '\n* `cachedir`, the second parameter of '
Packit Service 21c75c
            ':meth:`dnf.repo.Repo.__init__` is not optional (the method has '
Packit Service 21c75c
            'always been this way but the documentation was not matching)\n\n'
Packit Service 21c75c
            'API additions in 0.5.5:\n\n* extended description and an example '
Packit Service 21c75c
            'provided for :meth:`dnf.Base.fill_sack`\n* '
Packit Service 21c75c
            ':attr:`dnf.conf.Conf.proxy`\n* '
Packit Service 21c75c
            ':attr:`dnf.conf.Conf.proxy_username`\n* '
Packit Service 21c75c
            ':attr:`dnf.conf.Conf.proxy_password`\n* '
Packit Service 21c75c
            ':attr:`dnf.repo.Repo.proxy`\n* '
Packit Service 21c75c
            ':attr:`dnf.repo.Repo.proxy_username`\n* '
Packit Service 21c75c
            ':attr:`dnf.repo.Repo.proxy_password`\n\nBugs fixed in 0.5.5:\n\n',
Packit Service 21c75c
            # 0.6.0
Packit Service 21c75c
            '\n0.6.0 marks a new minor version of DNF and the first release to'
Packit Service 21c75c
            ' support advisories listing with the :ref:`udpateinfo command '
Packit Service 21c75c
            '<updateinfo_command-label>`.\n\nSupport for the :ref:`include '
Packit Service 21c75c
            'configuration directive <include-label>` has been added. Its '
Packit Service 21c75c
            "functionality reflects Yum's ``includepkgs`` but it has been "
Packit Service 21c75c
            'renamed to make it consistent with the ``exclude`` setting.\n\n'
Packit Service 21c75c
            'Group operations now produce a list of proposed marking changes '
Packit Service 21c75c
            'to group objects and the user is given a chance to accept or '
Packit Service 21c75c
            'reject them just like with an ordinary package transaction.\n\n'
Packit Service 21c75c
            'Bugs fixed in 0.6.0:\n\n',
Packit Service 21c75c
            # 0.6.1
Packit Service 21c75c
            '\nNew release adds :ref:`upgrade-type command '
Packit Service 21c75c
            '<upgrade_type_automatic-label>` to `dnf-automatic` for choosing '
Packit Service 21c75c
            'specific advisory type updates.\n\nImplemented missing '
Packit Service 21c75c
            ':ref:`history redo command <history_redo_command-label>` for '
Packit Service 21c75c
            'repeating transactions.\n\nSupports :ref:`gpgkey '
Packit Service 21c75c
            '<repo_gpgkey-label>` repo config, :ref:`repo_gpgcheck '
Packit Service 21c75c
            '<repo_gpgcheck-label>` and :ref:`gpgcheck <gpgcheck-label>` '
Packit Service 21c75c
            '[main] and Repo configs.\n\nDistributing new package '
Packit Service 21c75c
            ':ref:`dnf-yum <dnf_yum_package-label>` that provides '
Packit Service 21c75c
            '`/usr/bin/yum` as a symlink to `/usr/bin/dnf`.\n\nAPI additions '
Packit Service 21c75c
            'in 0.6.1:\n\n* `exclude`, the third parameter of '
Packit Service 21c75c
            ':meth:`dnf.Base.group_install` now also accepts glob patterns of '
Packit Service 21c75c
            'package names.\n\nBugs fixed in 0.6.1:\n\n',
Packit Service 21c75c
            # 0.6.2
Packit Service 21c75c
            '\nAPI additions in 0.6.2:\n\n* Now '
Packit Service 21c75c
            ':meth:`dnf.Base.package_install` method ignores already installed'
Packit Service 21c75c
            ' packages\n* `CliError` exception from :mod:`dnf.cli` documented'
Packit Service 21c75c
            '\n* `Autoerase`, `History`, `Info`, `List`, `Provides`, '
Packit Service 21c75c
            '`Repolist` commands do not force a sync of expired :ref:`metadata'
Packit Service 21c75c
            ' <metadata_synchronization-label>`\n* `Install` command does '
Packit Service 21c75c
            'installation only\n\nBugs fixed in 0.6.2:\n\n',
Packit Service 21c75c
            # 0.6.3
Packit Service 21c75c
            '\n:ref:`Deltarpm <deltarpm-label>` configuration option is set on'
Packit Service 21c75c
            ' by default.\n\nAPI additions in 0.6.3:\n\n* dnf-automatic adds '
Packit Service 21c75c
            ':ref:`motd emitter <emit_via_automatic-label>` as an alternative '
Packit Service 21c75c
            'output\n\nBugs fixed in 0.6.3:\n\n',
Packit Service 21c75c
            # 0.6.4
Packit Service 21c75c
            '\nAdded example code snippets into :doc:`use_cases`.\n\nShows '
Packit Service 21c75c
            'ordered groups/environments by `display_order` tag from :ref:`cli'
Packit Service 21c75c
            ' <grouplist_command-label>` and :doc:`api_comps` DNF API.\n\nIn '
Packit Service 21c75c
            'commands the environment group is specified the same as '
Packit Service 21c75c
            ':ref:`group <specifying_groups-label>`.\n\n'
Packit Service 21c75c
            ':ref:`skip_if_unavailable <skip_if_unavailable-label>` '
Packit Service 21c75c
            'configuration option affects the metadata only.\n\nadded '
Packit Service 21c75c
            '`enablegroups`, `minrate` and `timeout` :doc:`configuration '
Packit Service 21c75c
            'options <conf_ref>`\n\nAPI additions in 0.6.4:\n\nDocumented '
Packit Service 21c75c
            '`install_set` and `remove_set attributes` from '
Packit Service 21c75c
            ':doc:`api_transaction`.\n\nExposed `downloadsize`, `files`, '
Packit Service 21c75c
            '`installsize` attributes from :doc:`api_package`.\n\nBugs fixed '
Packit Service 21c75c
            'in 0.6.4:\n\n',
Packit Service 21c75c
            # 0.6.5
Packit Service 21c75c
            '\nPython 3 version of DNF is now default in Fedora 23 and later.'
Packit Service 21c75c
            '\n\nyum-dnf package does not conflict with yum package.\n\n'
Packit Service 21c75c
            '`dnf erase` was deprecated in favor of `dnf remove`.\n\nExtended '
Packit Service 21c75c
            'documentation of handling non-existent packages and YUM to DNF '
Packit Service 21c75c
            'transition in :doc:`cli_vs_yum`.\n\nAPI additions in 0.6.5:\n\n'
Packit Service 21c75c
            'Newly added `pluginconfpath` option in :doc:`configuration '
Packit Service 21c75c
            '<conf_ref>`.\n\nExposed `skip_if_unavailable` attribute from '
Packit Service 21c75c
            ':doc:`api_repos`.\n\nDocumented `IOError` exception of method '
Packit Service 21c75c
            '`fill_sack` from :class:`dnf.Base`.\n\nBugs fixed in 0.6.5:\n\n',
Packit Service 21c75c
            # 1.0.0
Packit Service 21c75c
            '\nImproved documentation of YUM to DNF transition in '
Packit Service 21c75c
            ':doc:`cli_vs_yum`.\n\n:ref:`Auto remove command '
Packit Service 21c75c
            '<autoremove_command-label>` does not remove `installonly` '
Packit Service 21c75c
            'packages.\n\n:ref:`Downgrade command <downgrade_command-label>` '
Packit Service 21c75c
            'downgrades to specified package version if that is lower than '
Packit Service 21c75c
            'currently installed one.\n\nDNF now uses :attr:`dnf.repo.Repo.id`'
Packit Service 21c75c
            ' as a default value for :attr:`dnf.repo.Repo.name`.\n\nAdded '
Packit Service 21c75c
            'support of repositories which use basic HTTP authentication.\n\n'
Packit Service 21c75c
            'API additions in 1.0.0:\n\n:doc:`configuration <conf_ref>` '
Packit Service 21c75c
            'options `username` and `password` (HTTP authentication)\n\n'
Packit Service 21c75c
            ':attr:`dnf.repo.Repo.username` and :attr:`dnf.repo.Repo.password`'
Packit Service 21c75c
            ' (HTTP authentication)\n\nBugs fixed in 1.0.0:\n\n',
Packit Service 21c75c
            # 1.0.1
Packit Service 21c75c
            '\nDNF follows the Semantic Versioning as defined at '
Packit Service 21c75c
            '`<http://semver.org/>`_.\n\nDocumented SSL '
Packit Service 21c75c
            ':doc:`configuration <conf_ref>` and :doc:`repository <api_repos>`'
Packit Service 21c75c
            ' options.\n\nAdded virtual provides allowing installation of DNF'
Packit Service 21c75c
            ' commands by their name in the form of\n'
Packit Service 21c75c
            '``dnf install dnf-command(name)``.\n\n'
Packit Service 21c75c
            ':doc:`dnf-automatic <automatic>` now by default waits random '
Packit Service 21c75c
            'interval between 0 and 300 seconds before any network '
Packit Service 21c75c
            'communication is performed.\n\n\nBugs fixed in 1.0.1:\n\n'
Packit Service 21c75c
        ]
Packit Service 21c75c
        rest = [
Packit Service 21c75c
            (None, [], ''),
Packit Service 21c75c
            ('0.3.1',
Packit Service 21c75c
             ['916657', '921294', '922521', '926871', '878826', '922664',
Packit Service 21c75c
              '892064', '919769'],
Packit Service 21c75c
             '\n'),
Packit Service 21c75c
            ('0.3.2', ['947258', '889202', '923384'], '\n'),
Packit Service 21c75c
            ('0.3.3', ['950722', '903775'], '\n'),
Packit Service 21c75c
            ('0.3.4', ['887317', '914919', '922667'], '\n'),
Packit Service 21c75c
            ('0.3.5', ['958452', '959990', '961549', '962188'], '\n'),
Packit Service 21c75c
            ('0.3.6',
Packit Service 21c75c
             ['966372', '965410', '963627', '965114', '964467', '963680',
Packit Service 21c75c
              '963133'],
Packit Service 21c75c
             '\n'),
Packit Service 21c75c
            ('0.3.7', ['916662', '967732'], '\n'),
Packit Service 21c75c
            ('0.3.8',
Packit Service 21c75c
             ['908491', '968159', '974427', '974866', '976652', '975858'],
Packit Service 21c75c
             '\n'),
Packit Service 21c75c
            ('0.3.9', ['964584', '979942', '980227', '981310'], '\n'),
Packit Service 21c75c
            ('0.3.10', ['977661', '984483', '986545'], '\n'),
Packit Service 21c75c
            ('0.3.11', ['979042', '977753', '996138', '993916'], '\n'),
Packit Service 21c75c
            ('0.4.0', ['997403', '1002508', '1002798'], '\n'),
Packit Service 21c75c
            ('0.4.1', ['998859', '1006366', '1008444', '1003220'], '\n'),
Packit Service 21c75c
            ('0.4.2', ['909744', '984529', '967798', '995459'], '\n'),
Packit Service 21c75c
            ('0.4.3', ['1013764', '1013773'], '\n'),
Packit Service 21c75c
            ('0.4.4', ['1017278'], '\n'),
Packit Service 21c75c
            ('0.4.5', ['1021087'], '\n'),
Packit Service 21c75c
            ('0.4.6',
Packit Service 21c75c
             ['878348', '880524', '1019957', '1020101', '1020934', '1023486'],
Packit Service 21c75c
             '\n'),
Packit Service 21c75c
            ('0.4.7', ['1019170', '1024776', '1025650'], '\n'),
Packit Service 21c75c
            ('0.4.8',
Packit Service 21c75c
             ['1014563', '1029948', '1030998', '1030297', '1030980'],
Packit Service 21c75c
             '\n'),
Packit Service 21c75c
            ('0.4.9',
Packit Service 21c75c
             ['884615', '963137', '991038', '1032455', '1034607', '1036116'],
Packit Service 21c75c
             '\n'),
Packit Service 21c75c
            ('0.4.10',
Packit Service 21c75c
             ['967264', '1018284', '1035164', '1036147', '1036211', '1038403',
Packit Service 21c75c
              '1038937', '1040255', '1044502', '1044981', '1044999'],
Packit Service 21c75c
             '\n'),
Packit Service 21c75c
            ('0.4.11',
Packit Service 21c75c
             ['1048402', '1048572', '1048716', '1048719', '1048988'],
Packit Service 21c75c
             '\n'),
Packit Service 21c75c
            ('0.4.12',
Packit Service 21c75c
             ['1045737', '1048468', '1048488', '1049025', '1051554'],
Packit Service 21c75c
             '\n'),
Packit Service 21c75c
            ('0.4.13',
Packit Service 21c75c
             ['909468', '1030440', '1046244', '1055051', '1056400'],
Packit Service 21c75c
             '\n'),
Packit Service 21c75c
            ('0.4.14', ['1062390', '1062847', '1063022', '1064148'],
Packit Service 21c75c
             '\n'),
Packit Service 21c75c
            ('0.4.15',
Packit Service 21c75c
             ['1048788', '1065728', '1065879', '1065959', '1066743'],
Packit Service 21c75c
             '\n'),
Packit Service 21c75c
            ('0.4.16', ['1069996'], '\n'),
Packit Service 21c75c
            ('0.4.17',
Packit Service 21c75c
             ['1059704', '1058224', '1069538', '1070598', '1070710', '1071323',
Packit Service 21c75c
              '1071455', '1071501', '1071518', '1071677'],
Packit Service 21c75c
             '\n'),
Packit Service 21c75c
            ('0.4.18', ['963710', '1067136', '1071212', '1071501'], '\n'),
Packit Service 21c75c
            ('0.4.19', ['1077173', '1078832', '1079621'], '\n'),
Packit Service 21c75c
            ('0.5.0',
Packit Service 21c75c
             ['1029022', '1051869', '1061780', '1062884', '1062889', '1063666',
Packit Service 21c75c
              '1064211', '1064226', '1073859', '1076884', '1079519', '1079932',
Packit Service 21c75c
              '1080331', '1080489', '1082230', '1083432', '1083767', '1084139',
Packit Service 21c75c
              '1084553', '1088166'],
Packit Service 21c75c
             '\n'),
Packit Service 21c75c
            ('0.5.1', ['1065882', '1081753', '1089864'], '\n'),
Packit Service 21c75c
            ('0.5.2',
Packit Service 21c75c
             ['963345', '1073457', '1076045', '1083679', '1092006', '1092777',
Packit Service 21c75c
              '1093888', '1094594', '1095580', '1095861', '1096506'],
Packit Service 21c75c
             '\n'),
Packit Service 21c75c
            ('0.5.3',
Packit Service 21c75c
             ['1047049', '1067156', '1093420', '1104757', '1105009', '1110800',
Packit Service 21c75c
              '1111569', '1111997', '1112669', '1112704'],
Packit Service 21c75c
             '\n'),
Packit Service 21c75c
            ('0.5.4',
Packit Service 21c75c
             ['1048973', '1108908', '1116544', '1116839', '1116845', '1117102',
Packit Service 21c75c
              '1117293', '1117678', '1118178', '1118796', '1119032'],
Packit Service 21c75c
             '\n'),
Packit Service 21c75c
            ('0.5.5',
Packit Service 21c75c
             ['1100946', '1117789', '1120583', '1121280', '1122900',
Packit Service 21c75c
              '1123688'],
Packit Service 21c75c
             '\n'),
Packit Service 21c75c
            ('0.6.0',
Packit Service 21c75c
             ['850912', '1055910', '1116666', '1118272', '1127206'],
Packit Service 21c75c
             '\n'),
Packit Service 21c75c
            ('0.6.1',
Packit Service 21c75c
             ['1132335', '1071854', '1131969', '908764', '1130878', '1130432',
Packit Service 21c75c
              '1118236', '1109915'],
Packit Service 21c75c
             '\n'),
Packit Service 21c75c
            ('0.6.2',
Packit Service 21c75c
             ['909856', '1134893', '1138700', '1070902', '1124316', '1136584',
Packit Service 21c75c
              '1135861', '1136223', '1122617', '1133830', '1121184'],
Packit Service 21c75c
             '\n'),
Packit Service 21c75c
            ('0.6.3',
Packit Service 21c75c
             ['1153543', '1151231', '1163063', '1151854', '1151740', '1110780',
Packit Service 21c75c
              '1149972', '1150474', '995537', '1149952', '1149350', '1170232',
Packit Service 21c75c
              '1147523', '1148208', '1109927'],
Packit Service 21c75c
             '\n'),
Packit Service 21c75c
            ('0.6.4',
Packit Service 21c75c
             ['1155877', '1175466', '1175466', '1186461', '1170156', '1184943',
Packit Service 21c75c
              '1177002', '1169165', '1167982', '1157233', '1138096', '1181189',
Packit Service 21c75c
              '1181397', '1175434', '1162887', '1156084', '1175098', '1174136',
Packit Service 21c75c
              '1055910', '1155918', '1119030', '1177394', '1154476'],
Packit Service 21c75c
             '\n'),
Packit Service 21c75c
            ('0.6.5',
Packit Service 21c75c
             ['1203151', '1187579', '1185977', '1195240', '1193914', '1195385',
Packit Service 21c75c
              '1160806', '1186710', '1207726', '1157233', '1190671', '1191579',
Packit Service 21c75c
              '1195325', '1154202', '1189083', '1193915', '1195661', '1190458',
Packit Service 21c75c
              '1194685', '1160950'],
Packit Service 21c75c
             '\n'),
Packit Service 21c75c
            ('1.0.0',
Packit Service 21c75c
             ['1215560', '1199648', '1208773', '1208018', '1207861', '1201445',
Packit Service 21c75c
              '1210275', '1191275', '1207965', '1215289'],
Packit Service 21c75c
             '\n'),
Packit Service 21c75c
            ('1.0.1',
Packit Service 21c75c
             ['1214968', '1222694', '1225246', '1213985', '1225277', '1223932',
Packit Service 21c75c
              '1223614', '1203661', '1187741'],
Packit Service 21c75c
             '')]
Packit Service 21c75c
        expected = (
Packit Service 21c75c
            (version, desc, issues, epilog)
Packit Service 21c75c
            for desc, (version, issues, epilog) in zip(descriptions, rest))
Packit Service 21c75c
        with open(notesfn) as notesfile:
Packit Service 21c75c
            self.assertItemsEqual(parser.parse_lines(notesfile), expected)
Packit Service 21c75c
Packit Service 21c75c
Packit Service 21c75c
if __name__ == '__main__':
Packit Service 21c75c
    main()