Esempio n. 1
0
def verify_sls(pdc_url, sl_dict):
    """
    Verifies that the service levels are properly formatted and exist in PDC
    :param pdc_url: a string of the URL to PDC
    :param sl_dict: a dictionary with the SLs of the request
    :return: None or ValidationError
    """
    # Make sure the EOL date is in the format of 2020-12-01
    eol_date_regex = re.compile(r'\d{4}-\d{2}-\d{2}')
    for sl, eol in sl_dict.items():
        if re.match(eol_date_regex, eol):
            eol_date = datetime.strptime(eol, '%Y-%m-%d').date()
            today = datetime.utcnow().date()
            if eol_date < today:
                raise rpkgError(
                    'The SL "{0}" is already expired'.format(eol))
            elif eol_date.month not in [6, 12] or eol_date.day != 1:
                raise rpkgError(
                    'The SL "{0}" must expire on June 1st or December 1st'
                    .format(eol))
        else:
            raise rpkgError(
                'The EOL date "{0}" is in an invalid format'.format(eol))

        sl_obj = get_sl_type(pdc_url, sl)
        if not sl_obj:
            raise rpkgError('The SL "{0}" is not in PDC'.format(sl))
Esempio n. 2
0
def query_pdc(server_url, endpoint, params, timeout=60):
    api_url = '{0}/rest_api/v1/{1}/'.format(
        server_url.rstrip('/'), endpoint.strip('/'))
    query_args = params
    while True:
        try:
            rv = requests.get(api_url, params=query_args, timeout=60)
        except ConnectionError as error:
            error_msg = ('The connection to PDC failed while trying to get '
                         'the active release branches. The error was: {0}'
                         .format(str(error)))
            raise rpkgError(error_msg)

        if not rv.ok:
            base_error_msg = ('The following error occurred while trying to '
                              'get the active release branches in PDC: {0}')
            raise rpkgError(base_error_msg.format(rv.text))

        rv_json = rv.json()
        for item in rv_json['results']:
            yield item

        if rv_json['next']:
            # Clear the query_args because they are baked into the "next" URL
            query_args = {}
            api_url = rv_json['next']
        else:
            # We've gone through every page, so we can return the found
            # branches
            break
Esempio n. 3
0
    def push(self):
        """Push changes to the remote repository"""
        # First check that we are not pushing to Fedora
        # FIXME: Ugly screen scraping
        push_remote = self.repo.git.config('--get',
                'branch.%s.remote' % self.branch_merge)
        if push_remote != self.remote:
            raise pyrpkg.rpkgError('Can only push to the Network Box ' + \
                    'infrastructure')

        # Then only push the relevant branches on the appropriate remote
        cmd = ['git', 'push', self.remote]

        # FIXME: Ugly screen scraping, functional programming style
        merged = map(lambda x: x.strip(),
                     filter(lambda x: re.match(self.branchre, x),
                            git.Git().branch('--merged',
                                             self.repo.active_branch.name
                                             ).split()))

        # Move the active branch to the end, so that merged upstream branches
        # get pushed first
        if self.repo.active_branch.name in merged:
            merged.remove(self.repo.active_branch.name)
            merged.append(self.repo.active_branch.name)

        if not merged:
            raise pyrpkg.rpkgError('Could not find any local branch to push')

        cmd.extend(merged)
        self._run_command(cmd, cwd=self.path)
Esempio n. 4
0
def get_fedora_release_state(config, cli_name, release):
    """
    Queries service page for release state. Query result is returned as json dict.

    :param config: ConfigParser object
    :param cli_name: string of the CLI's name (e.g. fedpkg)
    :param str release: short release name. Example: F29, F30, F29M, F30C, ...
    :return: state of the release or None if there is no such release
    :rtype: str
    """
    try:
        # url of the release service. It needs to be expanded by release name
        releases_service_url = config.get('{0}.bodhi'.format(cli_name),
                                          'releases_service',
                                          vars={'release': release})
    except (ValueError, NoOptionError, NoSectionError) as e:
        raise rpkgError('Could not get release state for Fedora '
                        '({0}): {1}.'.format(release, str(e)))

    try:
        rv = requests.get(releases_service_url, timeout=60)
    except ConnectionError as error:
        error_msg = ('The connection to Bodhi failed while trying to get '
                     'release state. The error was: {0}'.format(str(error)))
        raise rpkgError(error_msg)

    if rv.status_code == 404:
        # release wasn't found
        return None
    elif not rv.ok:
        base_error_msg = ('The following error occurred while trying to '
                          'get the release state in Bodhi: {0}')
        raise rpkgError(base_error_msg.format(rv.text))

    return rv.json().get('state')
Esempio n. 5
0
def get_sl_type(url, sl_name):
    """
    Gets the service level (SL) type from PDC
    :param url: a string of the URL to PDC
    :param sl_name: a string of the SL name
    :return: a dictionary representing the SL type or None
    """
    api_url = '{0}/rest_api/v1/component-sla-types/'.format(url.rstrip('/'))
    api_url_w_args = '{0}?{1}'.format(api_url, urlencode({'name': sl_name}))
    try:
        rv = requests.get(api_url_w_args, timeout=60)
    except ConnectionError as error:
        error_msg = ('The connection to PDC failed while trying to validate '
                     'the passed in service level. The error was: {0}'
                     .format(str(error)))
        raise rpkgError(error_msg)

    if not rv.ok:
        base_error_msg = ('The following error occurred while validating the '
                          'passed in service level in PDC: {0}')
        raise rpkgError(base_error_msg.format(rv.text))

    rv_json = rv.json()
    if rv_json['count'] == 1:
        return rv_json['results'][0]
    else:
        return None
Esempio n. 6
0
def new_pagure_issue(logger, url, token, title, body, cli_name):
    """
    Posts a new Pagure issue
    :param logger: A logger object
    :param url: a string of the URL to Pagure
    :param token: a string of the Pagure API token that has rights to create
    a ticket
    :param title: a string of the issue's title
    :param body: a string of the issue's body
    :return: a string of the URL to the created issue in the UI
    """
    api_url = '{0}/api/0'.format(url.rstrip('/'))
    new_issue_url = '{0}/releng/fedora-scm-requests/new_issue'.format(api_url)

    headers = {
        'Authorization': 'token {0}'.format(token),
        'Accept': 'application/json',
        'Content-Type': 'application/json'
    }
    payload = json.dumps({
        'title': title,
        'issue_content': body
    })
    try:
        rv = requests.post(
            new_issue_url, headers=headers, data=payload, timeout=60)
    except ConnectionError as error:
        error_msg = ('The connection to Pagure failed while trying to '
                     'create a new issue. The error was: {0}'.format(
                         str(error)))
        raise rpkgError(error_msg)

    base_error_msg = ('The following error occurred while creating a new '
                      'issue in Pagure: {0}')

    try:
        # Extract response error text (and debug data)
        rv_json = rv.json()
        logger.debug("Pagure API response: '{0}'".format(rv_json))
        rv_error = rv_json.get('error')
    except (ValueError, AttributeError):
        rv_error = rv.text

    if not rv.ok:
        # Lets see if the API returned an error message in JSON that we can
        # show the user
        # show hint for expired token
        if re.search(r"Invalid or expired token", rv_error, re.IGNORECASE):
            base_error_msg += '\nFor invalid or expired token refer to ' \
                '"{0} request-repo -h" to set a token in your user ' \
                'configuration.'.format(cli_name)
        raise rpkgError(base_error_msg.format(rv_error))

    return '{0}/releng/fedora-scm-requests/issue/{1}'.format(
        url.rstrip('/'), rv.json()['issue']['id'])
Esempio n. 7
0
def do_fork(logger, base_url, token, repo_name, namespace, cli_name):
    """
    Creates a fork of the project.
    :param logger: A logger object
    :param base_url: a string of the URL repository
    :param token: a string of the API token that has rights to make a fork
    :param repo_name: a string of the repository name
    :param namespace: a string determines a type of the repository
    :param cli_name: string of the CLI's name (e.g. fedpkg)
    :return: a bool; True when fork was created, False when already exists
    """
    api_url = '{0}/api/0'.format(base_url.rstrip('/'))
    fork_url = '{0}/fork'.format(api_url)

    headers = {
        'Authorization': 'token {0}'.format(token),
        'Accept': 'application/json',
        'Content-Type': 'application/json'
    }
    payload = json.dumps({
        'wait': True,
        'namespace': namespace,
        'repo': repo_name,
    })
    try:
        rv = requests.post(
            fork_url, headers=headers, data=payload, timeout=60)
    except ConnectionError as error:
        error_msg = ('The connection to API failed while trying to '
                     'create a new fork. The error was: {0}'.format(str(error)))
        raise rpkgError(error_msg)

    try:
        # Extract response error text (and debug data)
        rv_json = rv.json()
        logger.debug("Pagure API response: '{0}'".format(rv_json))
        rv_error = rv_json.get('error')
    except (ValueError, AttributeError):
        rv_error = rv.text

    base_error_msg = ('The following error occurred while creating a new fork: {0}')
    if not rv.ok:
        # Lets see if the API returned an error message in JSON that we can
        # show the user
        if re.search(r"Repo .+ already exists", rv_error, re.IGNORECASE):
            return False

        # show hint for expired token
        if re.search(r"Invalid or expired token", rv_error, re.IGNORECASE):
            base_error_msg += '\nFor invalid or expired token refer to ' \
                '"{0} fork -h" to set a token in your user ' \
                'configuration.'.format(cli_name)
        raise rpkgError(base_error_msg.format(rv_error))

    return True
Esempio n. 8
0
    def new_ticket(self, passwd, desc, build=None):
        """Open a new ticket on Rel-Eng trac instance.

        Get ticket component and assignee from current branch

        Create a new task ticket using username/password/desc

        Discover build nvr from module or optional build argument

        Return ticket number on success
        """

        override = self.override
        if not override:
            raise pyrpkg.rpkgError('Override tag is not required for %s' %
                                   self.branch_merge)

        uri = self.tracbaseurl % {'user': self.user, 'password': passwd}
        self.trac = offtrac.TracServer(uri)

        # Set trac's component and assignee from related distvar
        if self.distvar == 'fedora':
            component = 'koji'
            #owner = '*****@*****.**'
        elif self.distvar == 'rhel':
            component = 'epel'
            #owner = '*****@*****.**'

        # Raise if people request a tag against something that self updates
        build_target = self.anon_kojisession.getBuildTarget(self.target)
        if not build_target:
            raise pyrpkg.rpkgError('Unknown build target: %s' % self.target)
        dest_tag = self.anon_kojisession.getTag(build_target['dest_tag_name'])
        ancestors = self.anon_kojisession.getFullInheritance(
                                                    build_target['build_tag'])
        if dest_tag['id'] in [build_target['build_tag']] + \
                                  [ancestor['parent_id'] for
                                   ancestor in ancestors]:
            raise pyrpkg.rpkgError('Override tag is not required for %s' %
                                   self.branch_merge)

        if not build:
            build = self.nvr

        summary = 'Tag request %s for %s' % (build, override)
        type = 'task'
        try:
            ticket = self.trac.create_ticket(summary, desc,
                                             component=component,
                                             notify=True)
        except Exception, e:
            raise pyrpkg.rpkgError('Could not request tag %s: %s' % (build, e))
Esempio n. 9
0
    def checky(self, *args, **kwargs):
        # First only work on the remotes we care about
        fedpkg = 'pkgs.*\.fedoraproject\.org\/'
        # Do this in a try in case we're not in a repo
        try:
            remotes = [remote.name for remote in self.repo.remotes if
                       re.search(fedpkg, remote.url)]
        except:
            self.log.debug("Not in a repo, don't care about remotes")
            return func(self, *args, **kwargs)

        # Now loop through the remotes and see if any of them have
        # old style branch names
        for remote in remotes:
            # Check to see if the remote data matches the old style
            # This regex looks at the ref name which should be
            # "origin/f15/master or simliar.  This regex fills in the remote
            # name we care about and attempts to find any fedora/epel/olpc
            # branch that has the old style /master tail.
            refsre = r'%s/(f\d\d/master|f\d/master|fc\d/master|' % remote
            refsre += r'el\d/master|olpc\d/master)'
            for ref in self.repo.refs:
                if type(ref) == git.RemoteReference and \
                re.match(refsre, ref.name):
                    self.log.error('This repo has old style branches but '
                                   'upstream has converted to new style.\n'
                                   'Please run /usr/libexec/fedpkg-fixbranches '
                                   'to fix your repo.')
                    raise pyrpkg.rpkgError('Unconverted branches')
        return func(self, *args, **kwargs)
Esempio n. 10
0
    def _findmasterbranch(self):
        """Find the right "rpmfusion" for master"""

        # If we already have a koji session, just get data from the source
        if self._kojisession:
            rawhidetarget = self.kojisession.getBuildTarget('rawhide-free')
            desttag = rawhidetarget['dest_tag_name']
            desttag=desttag.split('-')
            desttag.remove('free')
            desttag=''.join(desttag)
            return desttag.replace('f', '')
        else:
            # We may not have Fedoras.  Find out what rawhide target does.
            try:
                rawhidetarget = self.anon_kojisession.getBuildTarget(
                    'rawhide-free')
            except:
                # We couldn't hit koji, bail.
                raise pyrpkg.rpkgError('Unable to query koji to find rawhide \
                                       target')
            desttag = rawhidetarget['dest_tag_name']
            desttag=desttag.split('-')
            desttag.remove('free')
            desttag=''.join(desttag)
            return desttag.replace('f', '')
Esempio n. 11
0
def do_add_remote(base_url, remote_base_url, username, repo, repo_name,
                  namespace):
    """
    Adds remote tracked repository
    :param base_url: a string of the URL repository
    :param remote_base_url: a string of the remote tracked repository
    :param username: a string of the (FAS) user name
    :param repo: object, current project git repository
    :param repo_name: a string of the repository name
    :param namespace: a string determines a type of the repository
    :return: a bool; True if remote was created, False when already exists
    """
    parsed_url = urlparse(remote_base_url)
    remote_url = '{0}://{1}/forks/{2}/{3}/{4}.git'.format(
        parsed_url.scheme,
        parsed_url.netloc,
        username,
        namespace,
        repo_name,
    )

    # check already existing remote
    for remote in repo.remotes:
        if remote.name == username:
            return False

    try:
        # create remote with username as its name
        repo.create_remote(username, url=remote_url)
    except git.exc.GitCommandError as e:
        error_msg = "During create remote:\n  {0}\n  {1}".format(
            " ".join(e.command), e.stderr)
        raise rpkgError(error_msg)
    return True
Esempio n. 12
0
def assert_valid_epel_package(name, branch):
    """
    Determines if the package is allowed to have an EPEL branch. If it can't,
    an rpkgError will be raised.
    :param name: a string of the package name
    :param branch: a string of the EPEL branch name (e.g. epel7)
    :return: None or rpkgError
    """
    # Extract any digits in the branch name to determine the EL version
    version = ''.join([i for i in branch if re.match(r'\d', i)])
    url = ('https://infrastructure.fedoraproject.org/repo/json/pkg_el{0}.json'
           .format(version))
    error_msg = ('The connection to infrastructure.fedoraproject.org failed '
                 'while trying to determine if this is a valid EPEL package.')
    try:
        rv = requests.get(url, timeout=60)
    except ConnectionError as error:
        error_msg += ' The error was: {0}'.format(str(error))
        raise rpkgError(error_msg)

    if not rv.ok:
        raise rpkgError(error_msg + ' The status code was: {0}'.format(
            rv.status_code))

    rv_json = rv.json()
    # Remove noarch from this because noarch is treated specially
    all_arches = set(rv_json['arches']) - set(['noarch'])
    # On EL6, also remove ppc and i386 as many packages will
    # have these arches missing and cause false positives
    if int(version) == 6:
        all_arches = all_arches - set(['ppc', 'i386'])
    # On EL7 and later, also remove ppc and i686 as many packages will
    # have these arches missing and cause false positives
    elif int(version) >= 7:
        all_arches = all_arches - set(['ppc', 'i686'])

    error_msg_two = (
        'This package is already an EL package and is built on all supported '
        'arches, therefore, it cannot be in EPEL. If this is a mistake or you '
        'have an exception, please contact the Release Engineering team.')
    for pkg_name, pkg_info in rv_json['packages'].items():
        # If the EL package is noarch only or is available on all supported
        # arches, then don't allow an EPEL branch
        if pkg_name == name:
            pkg_arches = set(pkg_info['arch'])
            if pkg_arches == set(['noarch']) or not (all_arches - pkg_arches):
                raise rpkgError(error_msg_two)
Esempio n. 13
0
    def load_rpmdefines(self):
        """Populate rpmdefines based on branch data.

        We need to overload this as we don't use the same branch names.
        """
        # We only match the top level branch name exactly.
        # Anything else is too dangerous and --dist should be used
        if re.match(r'nb\d\.\d$', self.branch_merge):
            # E.g: 'networkbox/nb5.0'
            self._distval = self.branch_merge.split('nb')[1]
            self._distvar = 'nbrs'
            self.dist = 'nb%s' % self.distval

        elif re.match(r'nbplayground$', self.branch_merge):
            # E.g: 'networkbox-nonfree/nbplayground'
            self._distval = self._findmasterbranch()
            self._distvar = 'nbrs'
            self.dist = 'nb%s' % self.distval

        elif re.match(r'nb-fedora\d\d$', self.branch_merge):
            self._distval = self.branch_merge.split("nb-fedora")[1]
            self._distvar = "fedora"
            self.dist = "fc%s" % self.distval
            self.mockconfig = "fedora-%s-%s" % (self._distval, self.localarch)

        elif re.match(r'nb-rhel\d$', self.branch_merge):
            self._distval = self.branch_merge.split('nb-rhel')[1]
            self._distvar = 'rhel'
            self.dist = 'el%s' % self.distval
            self.mockconfig = 'epel-%s-%s' % (self.distval, self.localarch)

        elif re.match(r'nb-epel\d$', self.branch_merge):
            self._distval = self.branch_merge.split('nb-epel')[1]
            self._distvar = 'rhel'
            self.dist = 'el%s' % self.distval
            self.mockconfig = 'epel-%s-%s' % (self.distval, self.localarch)

        else:
            raise pyrpkg.rpkgError('Could not find the dist from branch name '
                                   '%s\nPlease specify with --dist' %
                                   self.branch_merge)

        short_distval = self.distval.replace('.', '')

        self._rpmdefines = ["--define '_sourcedir %s'" % self.path,
                            "--define '_specdir %s'" % self.path,
                            "--define '_builddir %s'" % self.path,
                            "--define '_srcrpmdir %s'" % self.path,
                            "--define '_rpmdir %s'" % self.path,
                            "--define 'dist .%s'" % self.dist,
                            "--define '%s %s'" % (self.distvar, short_distval),
        # Note: Contrary to Fedora, we do not define the following:
        #                   "--define '%s 1'" % self.dist,
        # This is because it is completely broken in our case, because our
        # dist is 'nb5.0', and rpm chokes on the dot when evaluating the macro.
        # It becomes a choice between having a defined value that will never
        # work or not having it defined at all, and I chose the the latter to
        # avoid confusion (we never even tried to use it anyway).
                            ]
Esempio n. 14
0
    def fetchfedora(self):
        """Synchronise with the Fedora dist-git module."""
        try:
            self.fedora_remote.fetch('--no-tags')

        except git.cmd.GitCommandError as e:
            raise pyrpkg.rpkgError("%s\n(did you forget about the --name "
                                   "option?)" % e)
Esempio n. 15
0
    def load_rpmdefines(self):
        """Populate rpmdefines based on branch data"""

        # Determine runtime environment
        self._runtime_disttag = self._determine_runtime_env()

        # We only match the top level branch name exactly.
        # Anything else is too dangerous and --dist should be used
        # This regex works until after Fedora 99.
        if re.match(r'f\d\d$', self.branch_merge):
            self._distval = self.branch_merge.split('f')[1]
            self._distvar = 'fedora'
            self.dist = 'fc%s' % self._distval
            self.mockconfig = 'fedora-%s-%s' % (self._distval, self.localarch)
            self.override = 'f%s-override' % self._distval
            self._distunset = 'rhel'
        # Works until RHEL 10
        elif re.match(r'el\d$', self.branch_merge) or re.match(r'epel\d$', self.branch_merge):
            self._distval = self.branch_merge.split('el')[1]
            self._distvar = 'rhel'
            self.dist = 'el%s' % self._distval
            self.mockconfig = 'epel-%s-%s' % (self._distval, self.localarch)
            self.override = 'epel%s-override' % self._distval
            self._distunset = 'fedora'
        elif re.match(r'olpc\d$', self.branch_merge):
            self._distval = self.branch_merge.split('olpc')[1]
            self._distvar = 'olpc'
            self.dist = 'olpc%s' % self._distval
            self.override = 'dist-olpc%s-override' % self._distval
            self._distunset = 'rhel'
        # master
        elif re.match(r'master$', self.branch_merge):
            self._distval = self._findmasterbranch()
            self._distvar = 'fedora'
            self.dist = 'fc%s' % self._distval
            self.mockconfig = 'fedora-devel-%s' % self.localarch
            self.override = None
            self._distunset = 'rhel'
        # If we don't match one of the above, punt
        else:
            raise pyrpkg.rpkgError('Could not find the dist from branch name '
                                   '%s\nPlease specify with --dist' %
                                   self.branch_merge)
        self._rpmdefines = ["--define '_sourcedir %s'" % self.path,
                            "--define '_specdir %s'" % self.path,
                            "--define '_builddir %s'" % self.path,
                            "--define '_srcrpmdir %s'" % self.path,
                            "--define '_rpmdir %s'" % self.path,
                            "--define 'dist .%s'" % self.dist,
                            "--define '%s %s'" % (self._distvar, self._distval),
                            "--eval '%%undefine %s'" % self._distunset,
                            "--define '%s 1'" % self.dist]
        if self._runtime_disttag:
            if self.dist != self._runtime_disttag:
                # This means that the runtime is known, and is different from
                # the target, so we need to unset the _runtime_disttag
                self._rpmdefines.append("--eval '%%undefine %s'" %
                                        self._runtime_disttag)
Esempio n. 16
0
    def load_rpmdefines(self):
        """Populate rpmdefines based on branch data"""

        # Determine runtime environment
        self._runtime_disttag = self._determine_runtime_env()

        # We only match the top level branch name exactly.
        # Anything else is too dangerous and --dist should be used
        # This regex works until after Fedora 99.
        if re.match(r'f\d\d$', self.branch_merge):
            self._distval = self.branch_merge.split('f')[1]
            self._distvar = 'fedora'
            self.dist = 'fc%s' % self._distval
            self.mockconfig = 'fedora-%s-%s' % (self._distval, self.localarch)
            self.override = 'f%s-override' % self._distval
            self._distunset = 'rhel'
        # Works until RHEL 10
        elif re.match(r'el\d$', self.branch_merge) or re.match(
                r'epel\d$', self.branch_merge):
            self._distval = self.branch_merge.split('el')[1]
            self._distvar = 'rhel'
            self.dist = 'el%s' % self._distval
            self.mockconfig = 'epel-%s-%s' % (self._distval, self.localarch)
            self.override = 'epel%s-override' % self._distval
            self._distunset = 'fedora'
        # master
        elif re.match(r'master$', self.branch_merge):
            self._distval = self._findmasterbranch()
            self._distvar = 'fedora'
            self.dist = 'fc%s' % self._distval
            self.mockconfig = 'fedora-rawhide-%s' % self.localarch
            self.override = None
            self._distunset = 'rhel'
        # If we don't match one of the above, punt
        else:
            raise pyrpkg.rpkgError('Could not find the dist from branch name '
                                   '%s\nPlease specify with --dist' %
                                   self.branch_merge)
        self._rpmdefines = [
            "--define '_sourcedir %s'" % self.path,
            "--define '_specdir %s'" % self.path,
            "--define '_builddir %s'" % self.path,
            "--define '_srcrpmdir %s'" % self.path,
            "--define '_rpmdir %s'" % self.path,
            "--define 'dist .%s'" % self.dist,
            "--define '%s %s'" % (self._distvar, self._distval),
            "--eval '%%undefine %s'" % self._distunset,
            "--define '%s 1'" % self.dist
        ]
        if self._runtime_disttag:
            if self.dist != self._runtime_disttag:
                # This means that the runtime is known, and is different from
                # the target, so we need to unset the _runtime_disttag
                self._rpmdefines.append("--eval '%%undefine %s'" %
                                        self._runtime_disttag)
Esempio n. 17
0
def assert_new_tests_repo(name, dist_git_url):
    """
    Asserts that the tests repository name is new. Note that the repository name
    can be any arbitrary string, so just check if the repository already exists.

    :param name: a string with the package name
    :return: None or rpkgError
    """

    url = '{0}/tests/{1}'.format(dist_git_url, name)
    error_msg = (
        'The connection to dist-git failed '
        'trying to determine if this is a valid new tests '
        'repository name.')
    try:
        rv = requests.get(url, timeout=60)
    except ConnectionError as error:
        error_msg += ' The error was: {0}'.format(str(error))
        raise rpkgError(error_msg)

    if rv.ok:
        raise rpkgError("Repository {0} already exists".format(url))
Esempio n. 18
0
def config_get_safely(config, section, option):
    """
    Returns option from the user's configuration file. In case of missing
    section or option method throws an exception with a human-readable
    warning and a possible hint.
    The method should be used especially in situations when there are newly
    added sections/options into the config. In this case, there is a risk that
    the user's config wasn't properly upgraded.

    :param config: ConfigParser object
    :param section: section name in the config
    :param option: name of the option
    :return: option value from the right section
    :rtype: str
    """

    hint = (
        "First (if possible), refer to the help of the current command "
        "(-h/--help).\n"
        "There also might be a new version of the config after upgrade.\n"
        "Hint: you can check if you have 'fedpkg.conf.rpmnew' or "
        "'fedpkg.conf.rpmsave' in the config directory. If yes, try to merge "
        "your changes to the config with the maintainer provided version "
        "(or replace fedpkg.conf file with 'fedpkg.conf.rpmnew')."
    )

    try:
        return config.get(section, option)
    except NoSectionError:
        msg = "Missing section '{0}' in the config file.".format(section)
        raise rpkgError("{0}\n{1}".format(msg, hint))
    except NoOptionError:
        msg = "Missing option '{0}' in the section '{1}' of the config file.".format(
            option, section
        )
        raise rpkgError("{0}\n{1}".format(msg, hint))
    except Exception:
        raise
Esempio n. 19
0
    def load_spec(self):
        """This sets the spec attribute"""

        # We are not using the upstream load_spec because the file structure is
        # hard-coded

        # Get a list of files in the path we're looking at
        files = os.listdir(os.path.join(self.path, 'SPECS'))
        # Search the files for the first one that ends with ".spec"
        for __f in files:
            if __f.endswith('.spec') and not __f.startswith('.'):
                self._spec = os.path.join('SPECS', __f)
                return

        raise pyrpkg.rpkgError('No spec file found.')
Esempio n. 20
0
    def load_fedora_cert_files(self):
        """This loads the fedora_cert_file and fedora_ca_cert attributes"""
        import ConfigParser

        with open(self.fedora_kojiconfig) as f:
            config = ConfigParser.ConfigParser()
            config.readfp(f)

            if not config.has_section(os.path.basename(self.build_client)):
                raise pyrpkg.rpkgError("Can't find the [%s] section in the "
                                       "Koji config" % self.build_client)

            self._fedora_cert_file = os.path.expanduser(
                                config.get(self.build_client, "cert"))
            self._fedora_ca_cert = os.path.expanduser(
                                config.get(self.build_client, "serverca"))
Esempio n. 21
0
    def _findmasterbranch(self):
        """Find the right "nbrs" for master"""

        # Create a list of "nbrses"
        nbrses = []

        # Create a regex to find branches that exactly match nb#.#.  Should not
        # catch branches such as nb5.0-foobar
        branchre = r'nb\d$'

        # Find the repo refs
        for ref in self.repo.refs:
            # Only find the remote refs
            if type(ref) == git.refs.RemoteReference:
                # Search for branch name by splitting off the remote
                # part of the ref name and returning the rest.  This may
                # fail if somebody names a remote with / in the name...
                if re.match(branchre, ref.name.split('/', 1)[1]):
                    # Add just the simple nb#.# part to the list
                    nbrses.append(ref.name.split('/')[1])

        if nbrses:
            # Sort the list...
            nbrses.sort()

            # ... so we can take the last one and strip it from its 'nb'...
            latest_distval = nbrses[-1].strip('nb')

            # ... so we can add 1 to the last one and recreate the new dist
            return "%d" % (int(latest_distval)+1)

        else:
            # We may not have NBRSes. Find out what experimental target does.
            try:
                experimentaltarget = self.anon_kojisession.getBuildTarget(self.target)
            except:
                # We couldn't hit koji, bail.
                raise pyrpkg.rpkgError("Unable to query koji to find " \
                                       "experimental target")
            desttag = experimentaltarget['dest_tag_name']

            # Remove the trailing '-free' or '-nonfree'
            desttag = desttag.split('-')[0]

            return desttag.replace('nb', '')
Esempio n. 22
0
    def _findmasterbranch(self):
        """Find the right "fedora" for master"""

        # If we already have a koji session, just get data from the source
        if self._kojisession:
            rawhidetarget = self.kojisession.getBuildTarget('rawhide')
            desttag = rawhidetarget['dest_tag_name']
            return desttag.replace('f', '')

        # Create a list of "fedoras"
        fedoras = []

        # Create a regex to find branches that exactly match f##.  Should not
        # catch branches such as f14-foobar
        branchre = 'f\d\d$'

        # Find the repo refs
        for ref in self.repo.refs:
            # Only find the remote refs
            if type(ref) == git.RemoteReference:
                # Search for branch name by splitting off the remote
                # part of the ref name and returning the rest.  This may
                # fail if somebody names a remote with / in the name...
                if re.match(branchre, ref.name.split('/', 1)[1]):
                    # Add just the simple f## part to the list
                    fedoras.append(ref.name.split('/')[1])
        if fedoras:
            # Sort the list
            fedoras.sort()
            # Start with the last item, strip the f, add 1, return it.
            return(int(fedoras[-1].strip('f')) + 1)
        else:
            # We may not have Fedoras.  Find out what rawhide target does.
            try:
                rawhidetarget = self.anon_kojisession.getBuildTarget(
                                                              'rawhide')
            except:
                # We couldn't hit koji, bail.
                raise pyrpkg.rpkgError('Unable to query koji to find rawhide \
                                       target')
            desttag = rawhidetarget['dest_tag_name']
            return desttag.replace('f', '')
Esempio n. 23
0
    def _findmasterbranch(self):
        """Find the right "fedora" for master"""

        # If we already have a koji session, just get data from the source
        if self._kojisession:
            rawhidetarget = self.kojisession.getBuildTarget('rawhide')
            desttag = rawhidetarget['dest_tag_name']
            return desttag.replace('f', '')

        # Create a list of "fedoras"
        fedoras = []

        # Create a regex to find branches that exactly match f##.  Should not
        # catch branches such as f14-foobar
        branchre = 'f\d\d$'

        # Find the repo refs
        for ref in self.repo.refs:
            # Only find the remote refs
            if type(ref) == git.RemoteReference:
                # Search for branch name by splitting off the remote
                # part of the ref name and returning the rest.  This may
                # fail if somebody names a remote with / in the name...
                if re.match(branchre, ref.name.split('/', 1)[1]):
                    # Add just the simple f## part to the list
                    fedoras.append(ref.name.split('/')[1])
        if fedoras:
            # Sort the list
            fedoras.sort()
            # Start with the last item, strip the f, add 1, return it.
            return (int(fedoras[-1].strip('f')) + 1)
        else:
            # We may not have Fedoras.  Find out what rawhide target does.
            try:
                rawhidetarget = self.anon_kojisession.getBuildTarget('rawhide')
            except:
                # We couldn't hit koji, bail.
                raise pyrpkg.rpkgError('Unable to query koji to find rawhide \
                                       target')
            desttag = rawhidetarget['dest_tag_name']
            return desttag.replace('f', '')
Esempio n. 24
0
def sl_list_to_dict(sls):
    """
    Takes a list of SLs and returns them in a dictionary format. Any errors in
    the SLs will be raised as an rpkgError.
    :param sls: list of SLs in the format of sl_name:2017-12-25
    :return: dictionary in the format of {'sl_name': '2017-12-25'}
    """
    sl_dict = {}
    # Ensures the SL is in the format "security_fixes:2020-01-01"
    sl_regex = re.compile(r'^(.+)(?:\:)(\d{4}-\d{2}-\d{2})$')
    for sl in sls:
        sl_match = re.match(sl_regex, sl)
        if sl_match:
            sl_name = sl_match.groups()[0]
            sl_date = sl_match.groups()[1]
            sl_dict[sl_name] = sl_date
        else:
            raise rpkgError(
                'The SL "{0}" is in an invalid format'.format(sl))

    return sl_dict
Esempio n. 25
0
    def load_rpmdefines(self):
        '''
            Populate rpmdefines based on branch data
        '''
        try:
            osver = re.search(r'\d.*$', self.branch_merge).group()
        except AttributeError:
            raise pyrpkg.rpkgError(
                'Could not find the base OS ver from branch name'
                ' %s' % self.branch_merge)
        self._distval = osver
        self._distval = self._distval.replace('.', '_')

        self._disttag = 'el%s' % self._distval

        self._rpmdefines = [
            "--define '_topdir {0}'".format(self.path),
            "--define '_srcrpmdir {0}'".format(self.path),
            "--define '_rpmdir {0}'".format(self.path),
            "--define 'dist .{0}'".format(self._disttag),
            # int and float this to remove the decimal
            "--define '{0} 1'".format(self._disttag)
        ]
Esempio n. 26
0
    def get_review_bug(self, bug_id, namespace, pkg):
        """
        Gets a Bugzilla bug representing a Fedora package review and does as
        much validation as it can without authenticating to Bugzilla. This
        function was inspired by:
        https://github.com/fedora-infra/pkgdb2/blob/master/pkgdb2/api/extras.py
        https://pagure.io/pkgdb-cli/blob/master/f/pkgdb2client/utils.py
        :param bug_id: string or integer of the Bugzilla bug ID
        :param namespace: string of the dist-git namespace
        :param pkg: string of the package name
        """
        try:
            bug = self.client.getbug(bug_id)
        except Exception as error:
            raise rpkgError(
                'The Bugzilla bug could not be verified. The following '
                'error was encountered: {0}'.format(str(error)))

        # Do some basic validation on the bug
        pagure_namespace_to_component = {
            'rpms': 'Package Review',
            'container': 'Container Review',
            'modules': 'Module Review',
            'test-modules': 'Module Review'
        }
        pagure_namespace_to_product = {
            'rpms': ['Fedora', 'Fedora EPEL'],
            'container': ['Fedora Container Images'],
            'modules': ['Fedora Modules'],
            'test-modules': ['Fedora']
        }
        bz_proper_component = pagure_namespace_to_component.get(namespace)
        bz_proper_products = pagure_namespace_to_product.get(namespace)
        if bz_proper_component is None or bug.component != bz_proper_component:
            raise rpkgError('The Bugzilla bug provided is not the proper type')
        elif bug.product not in bz_proper_products:
            raise rpkgError(
                'The Bugzilla bug provided is not for "{0}"'.format(
                    '" or "'.join(bz_proper_products)))
        elif bug.assigned_to in ['', None, '*****@*****.**']:
            raise rpkgError(
                'The Bugzilla bug provided is not assigned to anyone')
        # Check if the review was approved
        flag_set = False
        for flag in bug.flags:
            name, status = flag.get('name'), flag.get('status')
            if name == 'fedora-review' and status == '+':
                flag_set = True
                update_dt = flag.get('modification_date')
                if update_dt:
                    dt = datetime.strptime(update_dt.value, '%Y%m%dT%H:%M:%S')
                    delta = datetime.utcnow().date() - dt.date()
                    if delta.days > 60:
                        raise rpkgError('The Bugzilla bug\'s review was '
                                        'approved over 60 days ago')
                break
        if not flag_set:
            raise rpkgError('The Bugzilla bug is not approved yet')
        # Check the format of the Bugzilla bug title
        tmp_summary = bug.summary.partition(':')[2]
        if not tmp_summary:
            raise rpkgError(
                'Invalid title for this Bugzilla bug (no ":" present)')
        if ' - ' not in tmp_summary:
            raise rpkgError(
                'Invalid title for this Bugzilla bug (no "-" present)')
        pkg_in_bug = tmp_summary.split(' - ', 1)[0].strip()
        if pkg != pkg_in_bug:
            error = ('The package in the Bugzilla bug "{0}" doesn\'t match '
                     'the one provided "{1}"'.format(pkg_in_bug, pkg))
            raise rpkgError(error)
        return bug
Esempio n. 27
0
    def sources(self, outdir=None):
        """Download source files"""

        #  See also:
        # https://lists.fedoraproject.org/pipermail/buildsys/2014-July/004313.html
        #
        # in 'super' the sources function expects a file named 'sources' to be in the base directory.
        # A patch has been sent to upstream to allow a more flexible location.
        #
        # This code doesn't work due to:
        #              archive.strip().split('  ', 1) # patch provided to upstream to fix
        #
        #              url = '%s/%s/%s/%s/%s' % (self.lookaside, self.module_name,
        #                                        file.replace(' ', '%20'),
        #                                        csum, file.replace(' ', '%20'))
        #
        #os.symlink(os.path.join(self.path, '.{0}.metadata'.format(self.module_name)), os.path.join(self.path, 'sources'))
        #super(Commands, self).sources(outdir=None)
        #os.unlink(os.path.join(self.path, 'sources'))

        # The following is copied from rpkg/__init__.py:sources with minor changes
        try:
            archives = open(
                os.path.join(self.path,
                             '.{0}.metadata'.format(self.module_name)),
                'r').readlines()
        except IOError as e:
            raise pyrpkg.rpkgError('%s is not a valid repo: %s' %
                                   (self.path, e))
        # Default to putting the files where the module is
        if not outdir:
            outdir = self.path
        for archive in archives:
            try:
                # This strip / split is kind a ugly, but checksums shouldn't have
                # two spaces in them.  sources file might need more structure in the
                # future
                csum, file = archive.strip().split(None, 1)
            except ValueError:
                raise pyrpkg.rpkgError('Malformed sources file.')

            # The default lookaside hash is stored in centpkg.conf, but there is
            # a mix of md5 and sha sums in the CentOS lookaside, here we divine
            # which one we are using

            sum_lengths = {
                128: 'sha512',
                64: 'sha256',
                40: 'sha1',
                32: 'md5',
            }

            self.lookasidehash = sum_lengths[len(csum)]

            # If a directory is specified in the metadata file, append it to
            # outdir
            if os.path.dirname(file):
                outdir = os.path.join(self.path, os.path.dirname(file))
                file = os.path.basename(file)

            # Create the output directory if it's not checked into git
            if not os.path.exists(outdir):
                self.log.info("Creating OUTDIR: {0}".format(outdir))
                os.makedirs(outdir)

            outfile = os.path.join(outdir, file)
            # See if we already have a valid copy downloaded
            if os.path.exists(outfile):
                if self._verify_file(outfile, csum, self.lookasidehash):
                    continue
            self.log.info("Downloading %s" % (file))
            url = '%s/%s/%s/%s' % (
                self.lookaside,
                self.module_name,
                self.branch_merge,
                csum,
            )
            command = [
                'curl', '-H', 'Pragma:', '-o', outfile, '-R', '-S', '--fail'
            ]
            if self.quiet:
                command.append('-s')
            command.append(url)
            self._run_command(command)
            if not self._verify_file(outfile, csum, self.lookasidehash):
                raise pyrpkg.rpkgError('%s failed checksum' % file)

        return