コード例 #1
0
ファイル: test_cli.py プロジェクト: thegreyd/elliott
 def test_id_convert(self):
     self.assertEqual(cli_opts.id_convert(["1", "2", "3,4,5"]),
                      [1, 2, 3, 4, 5])
     self.assertEqual(cli_opts.id_convert(["1,2,3", "4", "5"]),
                      [1, 2, 3, 4, 5])
     self.assertEqual(cli_opts.id_convert(["1", "2", "3", "4", "5"]),
                      [1, 2, 3, 4, 5])
     self.assertEqual(cli_opts.id_convert(["1,2,3,4,5"]), [1, 2, 3, 4, 5])
コード例 #2
0
def repair_bugs(runtime, advisory, auto, id, original_state, new_state,
                comment, close_placeholder, use_jira, noop,
                default_advisory_type, bug_tracker):
    changed_bug_count = 0

    if default_advisory_type is not None:
        advisory = find_default_advisory(runtime, default_advisory_type)

    if auto:
        click.echo("Fetching Advisory(errata_id={})".format(advisory))
        if use_jira:
            raw_bug_list = [
                issue["key"]
                for issue in errata.get_jira_issue_from_advisory(advisory)
            ]
        else:
            e = elliottlib.errata.Advisory(errata_id=advisory)
            raw_bug_list = e.errata_bugs
    else:
        click.echo("Bypassed fetching erratum, using provided BZs")
        raw_bug_list = cli_opts.id_convert(id)

    green_print("Getting bugs for advisory")

    # Fetch bugs in parallel because it can be really slow doing it
    # one-by-one when you have hundreds of bugs
    pbar_header("Fetching data for {} bugs: ".format(len(raw_bug_list)),
                "Hold on a moment, we have to grab each one", raw_bug_list)
    pool = ThreadPool(cpu_count())
    click.secho("[", nl=False)

    attached_bugs = pool.map(
        lambda bug: progress_func(lambda: bug_tracker.get_bug(bug), '*'),
        raw_bug_list)
    # Wait for results
    pool.close()
    pool.join()
    click.echo(']')

    green_print("Got bugs for advisory")
    for bug in attached_bugs:
        if close_placeholder and "Placeholder" in bug.summary:
            # if set close placeholder, ignore bug state
            bug_tracker.update_bug_status(bug, "CLOSED")
            changed_bug_count += 1
        else:
            if bug.status in original_state:
                bug_tracker.update_bug_status(bug, new_state)
                # only add comments for non-placeholder bug
                if comment and not noop:
                    bug_tracker.add_comment(bug, comment, private=False)
                changed_bug_count += 1

    green_print("{} bugs successfully modified (or would have been)".format(
        changed_bug_count))
コード例 #3
0
ファイル: __main__.py プロジェクト: sfowl/elliott
def remove_bugs(runtime, advisory, default_advisory_type, id):
    """Remove given BUGS from ADVISORY.

    Remove bugs that have been attached an advisory:

\b
    $ elliott --group openshift-3.7 remove-bugs --id 123456 --advisory 1234123

    Remove two bugs from default rpm advisory. Note that --group is required
    because default advisory is from ocp-build-data:

\b
    $ elliott --group openshift-3.7 remove-bugs --id 123456 --id 3412311 --use-default-advisory rpm


"""
    if bool(advisory) == bool(default_advisory_type):
        raise click.BadParameter(
            "Specify exactly one of --use-default-advisory or advisory arg")

    runtime.initialize()
    bz_data = runtime.gitdata.load_data(key='bugzilla').data
    bzapi = elliottlib.bzutil.get_bzapi(bz_data)

    bug_ids = [bzapi.getbug(i) for i in cli_opts.id_convert(id)]

    green_prefix("Found {} bugs:".format(len(bug_ids)))
    click.echo(" {}".format(", ".join([str(b.bug_id) for b in bug_ids])))

    if default_advisory_type is not None:
        advisory = find_default_advisory(runtime, default_advisory_type)

    if advisory is not False:
        try:
            advs = Erratum(errata_id=advisory)
        except GSSError:
            exit_unauthenticated()

        if advs is False:
            raise ElliottFatalError(
                "Error: Could not locate advisory {advs}".format(
                    advs=advisory))

        try:
            green_prefix("Removing {count} bugs from advisory:".format(
                count=len(bug_ids)))
            click.echo(" {advs}".format(advs=advisory))
            advs.removeBugs([bug.id for bug in bug_ids])
            advs.commit()
        except ErrataException as ex:
            raise ElliottFatalError(getattr(ex, 'message', repr(ex)))
コード例 #4
0
def attach_bugs_cli(runtime: Runtime, advisory, default_advisory_type, bug_ids,
                    report, output, noop):
    """Attach OCP Bugs to ADVISORY
Print bug details with --report
For attaching use --advisory, --use-default-advisory <TYPE>

    Print bug report (no attach)

\b
    $ elliott -g openshift-4.10 attach-bugs 8675309 7001337 --report


    Print bug report for jira bugs (no attach)

\b
    $ USEJIRA=true elliott -g openshift-4.10 attach-bugs OCPBUGS-10 OCPBUGS-9 --report


    Attach bugs to the advisory 123456

\b
    $ elliott -g openshift-4.10 attach-bugs 8675309 7001337 --advisory 123456


    Attach bugs to the 4.10.2 assembly defined image advisory

\b
    $ elliott -g openshift-4.10 --assembly 4.10.2 attach-bugs 8675309 7001337 --use-default-advisory image

"""
    if advisory and default_advisory_type:
        raise click.BadParameter(
            "Use only one of --use-default-advisory <TYPE> or --advisory <ADVISORY_ID>"
        )

    runtime.initialize()
    if default_advisory_type is not None:
        advisory = find_default_advisory(runtime, default_advisory_type)

    bug_trackers = runtime.bug_trackers
    if runtime.use_jira or runtime.only_jira:
        bug_ids = cli_opts.id_convert_str(bug_ids)
        attach_bugs(runtime, advisory, bug_ids, report, output, noop,
                    bug_trackers['jira'])
    else:
        bug_ids = cli_opts.id_convert(bug_ids)
        attach_bugs(runtime, advisory, bug_ids, report, output, noop,
                    bug_trackers['bugzilla'])
コード例 #5
0
def remove_bugs_cli(runtime, advisory_id, default_advisory_type, bug_ids, remove_all, noop):
    """Remove given BUGS from ADVISORY.

    Remove bugs that have been attached an advisory:

\b
    $ elliott --group openshift-4.10 remove-bugs 123456 --advisory 1234123

    Remove two bugs from default image advisory

\b
    $ elliott --group openshift-4.10 --assembly 4.10.19 remove-bugs 123456 3412311 --use-default-advisory image

    Remove all bugs from default image advisory

\b
    $ elliott --group openshift-4.10 --assembly 4.10.19 remove-bugs --all --use-default-advisory image

"""
    if bool(remove_all) == bool(bug_ids):
        raise click.BadParameter("Specify either <BUGID> or --all param")
    if bool(advisory_id) == bool(default_advisory_type):
        raise click.BadParameter("Specify exactly one of --use-default-advisory or advisory arg")

    runtime.initialize()
    if default_advisory_type is not None:
        advisory_id = find_default_advisory(runtime, default_advisory_type)

    bug_trackers = runtime.bug_trackers
    if runtime.use_jira or runtime.only_jira:
        bug_ids = cli_opts.id_convert_str(bug_ids)
        remove_bugs(advisory_id, bug_ids, remove_all,
                    bug_trackers['jira'], noop)
    else:
        bug_ids = cli_opts.id_convert(bug_ids)
        remove_bugs(advisory_id, bug_ids, remove_all,
                    bug_trackers['bugzilla'], noop)
コード例 #6
0
def find_bugs_cli(runtime, advisory, default_advisory_type, mode, status, id,
                  cve_trackers, from_diff, flag, report,
                  into_default_advisories, noop):
    """Find Red Hat Bugzilla bugs or add them to ADVISORY. Bugs can be
"swept" into the advisory either automatically (--mode sweep), or by
manually specifying one or more bugs using --mode list and the --id option.
Use cases are described below:

    Note: Using --id without --add is basically pointless

SWEEP: For this use-case the --group option MUST be provided. The
--group automatically determines the correct target-releases to search
for bugs claimed to be fixed, but not yet attached to advisories.

LIST: The --group option is not required if you are specifying bugs
manually. Provide one or more --id's for manual bug addition. In LIST
mode you must provide a list of IDs to attach with the --id option.

DIFF: For this use case, you must provide the --between option using two
URLs to payloads.

QE: Find MODIFIED bugs for the target-releases, and set them to ON_QA.
The --group option MUST be provided. Cannot be used in combination
with --into-default-advisories, --add, --into-default-advisories

Using --use-default-advisory without a value set for the matching key
in the build-data will cause an error and elliott will exit in a
non-zero state. Use of this option silently overrides providing an
advisory with the --add option.

    Automatically add bugs with target-release matching 3.7.Z or 3.7.0
    to advisory 123456:

\b
    $ elliott --group openshift-3.7 find-bugs --mode sweep --add 123456

    List bugs that WOULD be added to an advisory and have set the bro_ok flag on them (NOOP):

\b
    $ elliott --group openshift-3.7 find-bugs --mode sweep --flag bro_ok

    Attach bugs to their correct default advisories, e.g. operator-related bugs go to "extras" instead of the default "image":

\b
    $ elliott --group=openshift-4.4 find-bugs --mode=sweep --into-default-advisories

    Add two bugs to advisory 123456. Note that --group is not required
    because we're not auto searching:

\b
    $ elliott find-bugs --mode list --id 8675309 --id 7001337 --add 123456

    Automatically find bugs for openshift-4.1 and attach them to the
    rpm advisory defined in ocp-build-data:

\b
    $ elliott --group=openshift-4.1 --mode sweep --use-default-advisory rpm

    Find bugs for 4.6 that are in MODIFIED state, and set them to ON_QA:

\b
    $ elliott --group=openshift-4.6 --mode qe
"""
    if mode != 'list' and len(id) > 0:
        raise click.BadParameter(
            "Combining the automatic and manual bug attachment options is not supported"
        )

    if mode == 'list' and len(id) == 0:
        raise click.BadParameter(
            "When using mode=list, you must provide a list of bug IDs")

    if mode == 'payload' and not len(from_diff) == 2:
        raise click.BadParameter(
            "If using mode=payload, you must provide two payloads to compare")

    if sum(
            map(bool,
                [advisory, default_advisory_type, into_default_advisories
                 ])) > 1:
        raise click.BadParameter(
            "Use only one of --use-default-advisory, --add, or --into-default-advisories"
        )

    if mode == 'qe' and sum(
            map(bool,
                [advisory, default_advisory_type, into_default_advisories
                 ])) > 0:
        raise click.BadParameter(
            "--mode=qe does not operate on an advisory. Do not specify any of `--use-default-advisory`, `--add`, or `--into-default-advisories`"
        )

    runtime.initialize()
    bz_data = runtime.gitdata.load_data(key='bugzilla').data
    bzapi = bzutil.get_bzapi(bz_data)

    if default_advisory_type is not None:
        advisory = find_default_advisory(runtime, default_advisory_type)

    if mode == 'sweep' or mode == 'qe':
        if mode == 'qe':
            status = ['MODIFIED']
        green_prefix(
            f"Searching for bugs with status {' '.join(status)} and target release(s):"
        )
        click.echo(" {tr}".format(tr=", ".join(bz_data['target_release'])))
        bugs = bzutil.search_for_bugs(
            bz_data,
            status,
            filter_out_security_bugs=not (cve_trackers),
            verbose=runtime.debug)
    elif mode == 'list':
        bugs = [bzapi.getbug(i) for i in cli_opts.id_convert(id)]
    elif mode == 'diff':
        click.echo(runtime.working_dir)
        bug_id_strings = openshiftclient.get_bug_list(runtime.working_dir,
                                                      from_diff[0],
                                                      from_diff[1])
        bugs = [bzapi.getbug(i) for i in bug_id_strings]

    # Some bugs should goes to CPaaS so we should ignore them
    m = re.match(
        r"rhaos-(\d+).(\d+)", runtime.branch
    )  # extract OpenShift version from the branch name. there should be a better way...
    if not m:
        raise ElliottFatalError(
            f"Unable to determine OpenShift version from branch name {runtime.branch}."
        )
    major_version = int(m[1])
    minor_version = int(m[2])

    def _filter_bugs(bugs):  # returns a list of bugs that should be processed
        r = []
        ignored_repos = set()  # GitHub repos that should be ignored
        if major_version == 4 and minor_version == 5:
            # per https://issues.redhat.com/browse/ART-997: these repos should have their release-4.5 branches ignored by ART:
            ignored_repos = {
                "https://github.com/openshift/aws-ebs-csi-driver",
                "https://github.com/openshift/aws-ebs-csi-driver-operator",
                "https://github.com/openshift/cloud-provider-openstack",
                "https://github.com/openshift/csi-driver-nfs",
                "https://github.com/openshift/csi-driver-manila-operator"
            }
        for bug in bugs:
            external_links = [
                ext["type"]["full_url"].replace("%id%", ext["ext_bz_bug_id"])
                for ext in bug.external_bugs
            ]  # https://github.com/python-bugzilla/python-bugzilla/blob/7aa70edcfea9b524cd8ac51a891b6395ca40dc87/bugzilla/_cli.py#L750
            public_links = [
                runtime.get_public_upstream(url)[0] for url in external_links
            ]  # translate openshift-priv org to openshift org when comparing to filter (i.e. prow may link to a PR on the private org).
            # if a bug has 1 or more public_links, we should ignore the bug if ALL of the public_links are ANY of `ignored_repos`
            if public_links and all(
                    map(
                        lambda url: any(
                            map(
                                lambda repo: url != repo and url.startswith(
                                    repo), ignored_repos)), public_links)):
                continue
            r.append(bug)
        return r

    if len(
            id
    ) == 0:  # unless --id is given, we should ignore bugs that don't belong to ART. e.g. some bugs should go to CPaaS
        filtered_bugs = _filter_bugs(bugs)
        green_prefix(
            f"Found {len(filtered_bugs)} bugs ({len(bugs) - len(filtered_bugs)} ignored):"
        )
        bugs = filtered_bugs
    else:
        green_prefix("Found {} bugs:".format(len(bugs)))
    click.echo(" {}".format(", ".join([str(b.bug_id) for b in bugs])))

    if mode == 'qe':
        for bug in bugs:
            bzutil.set_state(bug, 'ON_QA', noop=noop)

    if len(flag) > 0:
        for bug in bugs:
            for f in flag:
                if noop:
                    click.echo(
                        f'Would have updated bug {bug.id} by setting flag {f}')
                    continue
                bug.updateflags({f: "+"})

    if report:
        green_print("{:<8s} {:<25s} {:<12s} {:<7s} {:<10s} {:60s}".format(
            "ID", "COMPONENT", "STATUS", "SCORE", "AGE", "SUMMARY"))
        for bug in bugs:
            created_date = datetime.datetime.strptime(str(bug.creation_time),
                                                      '%Y%m%dT%H:%M:%S')
            days_ago = (datetime.datetime.today() - created_date).days
            click.echo(
                "{:<8d} {:<25s} {:<12s} {:<7s} {:<3d} days   {:60s} ".format(
                    bug.id, bug.component, bug.status,
                    bug.cf_pm_score if hasattr(bug, "cf_pm_score") else '?',
                    days_ago, bug.summary[:60]))

    if advisory and not default_advisory_type:  # `--add ADVISORY_NUMBER` should respect the user's wish and attach all available bugs to whatever advisory is specified.
        errata.add_bugs_with_retry(advisory, bugs, noop=noop)
        return

    # If --use-default-advisory or --into-default-advisories is given, we need to determine which bugs should be swept into which advisory.
    # Otherwise we don't need to sweep bugs at all.
    if not (into_default_advisories or default_advisory_type):
        return
    impetus_bugs = {
    }  # key is impetus ("rpm", "image", "extras"), value is a set of bug IDs.
    # @lmeyer: simple and stupid would still be keeping the logic in python, possibly with config flags for branched logic. until that logic becomes too ugly to keep in python, i suppose..
    if major_version < 4:  # for 3.x, all bugs should go to the rpm advisory
        impetus_bugs["rpm"] = set(bugs)
    else:  # for 4.x
        # optional operators bugs should be swept to the "extras" advisory, while other bugs should be swept to "image" advisory.
        # a way to identify operator-related bugs is by its "Component" value. temporarily hardcode here until we need to move it to ocp-build-data.
        extra_components = {
            "Logging", "Service Brokers", "Metering Operator",
            "Node Feature Discovery Operator"
        }  # we will probably find more
        impetus_bugs["extras"] = {
            b
            for b in bugs if b.component in extra_components
        }
        impetus_bugs["image"] = {
            b
            for b in bugs if b.component not in extra_components
        }

    if default_advisory_type and impetus_bugs.get(default_advisory_type):
        errata.add_bugs_with_retry(advisory,
                                   impetus_bugs[default_advisory_type],
                                   noop=noop)
    elif into_default_advisories:
        for impetus, bugs in impetus_bugs.items():
            if bugs:
                errata.add_bugs_with_retry(
                    runtime.group_config.advisories[impetus], bugs, noop=noop)
コード例 #7
0
ファイル: __main__.py プロジェクト: sfowl/elliott
def repair_bugs(runtime, advisory, auto, id, original_state, new_state, noop,
                default_advisory_type):
    """Move bugs attached to the advisory from one state to another
state. This is useful if the bugs have changed states *after* they
were attached. Similar to `find-bugs` but in reverse. `repair-bugs`
begins by reading bugs from an advisory, whereas `find-bugs` reads
from bugzilla.

This looks at attached bugs in the provided --from state and moves
them to the provided --to state.

\b
    Background: This is intended for bugs which went to MODIFIED, were
    attached to advisories, set to ON_QA, and then failed
    testing. When this happens their state is reset back to ASSIGNED.

Using --use-default-advisory without a value set for the matching key
in the build-data will cause an error and elliott will exit in a
non-zero state. Most likely you will only want to use the `rpm` state,
but that could change in the future. Use of this option conflicts with
providing an advisory with the -a/--advisory option.

    Move bugs on 123456 FROM the MODIFIED state back TO ON_QA state:

\b
    $ elliott --group=openshift-4.1 repair-bugs --auto --advisory 123456 --from MODIFIED --to ON_QA

    As above, but using the default RPM advisory defined in ocp-build-data:

\b
    $ elliott --group=openshift-4.1 repair-bugs --auto --use-default-advisory rpm --from MODIFIED --to ON_QA

    The previous examples could also be ran like this (MODIFIED and ON_QA are both defaults):

\b
    $ elliott --group=openshift-4.1 repair-bugs --auto --use-default-advisory rpm

    Bug ids may be given manually instead of using --auto:

\b
    $ elliott --group=openshift-4.1 repair-bugs --id 170899 --id 8675309 --use-default-advisory rpm
"""
    if auto and len(id) > 0:
        raise click.BadParameter(
            "Combining the automatic and manual bug modification options is not supported"
        )

    if not auto and len(id) == 0:
        # No bugs were provided
        raise click.BadParameter(
            "If not using --auto then one or more --id's must be provided")

    if advisory and default_advisory_type:
        raise click.BadParameter(
            "Use only one of --use-default-advisory or --advisory")

    if len(id) == 0 and advisory is None and default_advisory_type is None:
        # error, no bugs, advisory, or default selected
        raise click.BadParameter(
            "No input provided: Must use one of --id, --advisory, or --use-default-advisory"
        )

    # Load bugzilla infomation and get a reference to the api
    runtime.initialize()
    bz_data = runtime.gitdata.load_data(key='bugzilla').data
    bzapi = elliottlib.bzutil.get_bzapi(bz_data)
    changed_bug_count = 0
    attached_bugs = []

    if default_advisory_type is not None:
        advisory = find_default_advisory(runtime, default_advisory_type)

    raw_bug_list = []
    if auto:
        click.echo("Fetching Erratum(errata_id={})".format(advisory))
        e = Erratum(errata_id=advisory)
        raw_bug_list = e.errata_bugs
    else:
        click.echo("Bypassed fetching erratum, using provided BZs")
        raw_bug_list = cli_opts.id_convert(id)

    green_print("Getting bugs for advisory")

    # Fetch bugs in parallel because it can be really slow doing it
    # one-by-one when you have hundreds of bugs
    pbar_header("Fetching data for {} bugs: ".format(len(raw_bug_list)),
                "Hold on a moment, we have to grab each one", raw_bug_list)
    pool = ThreadPool(cpu_count())
    click.secho("[", nl=False)

    attached_bugs = pool.map(
        lambda bug: progress_func(lambda: bzapi.getbug(bug), '*'),
        raw_bug_list)
    # Wait for results
    pool.close()
    pool.join()
    click.echo(']')

    green_print("Got bugs for advisory")
    for bug in attached_bugs:
        if bug.status in original_state:
            changed_bug_count += 1
            elliottlib.bzutil.set_state(bug, new_state, noop=noop)

    green_print("{} bugs successfullly modified (or would have been)".format(
        changed_bug_count))
コード例 #8
0
def find_bugs_cli(runtime, advisory, default_advisory_type, mode, check_builds,
                  status, exclude_status, id, cve_trackers, from_diff, flag,
                  report, into_default_advisories, noop):
    """Find Red Hat Bugzilla bugs or add them to ADVISORY. Bugs can be
"swept" into the advisory either automatically (--mode sweep), or by
manually specifying one or more bugs using --mode list with the --id option.
Use cases are described below:

    Note: Using --id without --add is basically pointless

SWEEP: For this use-case the --group option MUST be provided. The
--group automatically determines the correct target-releases to search
for bugs claimed to be fixed, but not yet attached to advisories.
--check-builds flag forces bug validation with attached builds to rpm advisory. It assumes builds have been attached and only attaches bugs with matching builds.
default --status: ['MODIFIED', 'ON_QA', 'VERIFIED']

LIST: The --group option is not required if you are specifying bugs
manually. Provide one or more --id's for manual bug addition. In LIST
mode you must provide a list of IDs to attach with the --id option.

DIFF: For this use case, you must provide the --between option using two
URLs to payloads.

QE: Find MODIFIED bugs for the target-releases, and set them to ON_QA.
The --group option MUST be provided. Cannot be used in combination
with --add, --use-default-advisory, --into-default-advisories, --exclude-status.

BLOCKER: List active blocker+ bugs for the target-releases.
The --group option MUST be provided. Cannot be used in combination
with --add, --use-default-advisory, --into-default-advisories.
default --status: ['NEW', 'ASSIGNED', 'POST', 'MODIFIED', 'ON_DEV', 'ON_QA']
Use --exclude_status to filter out from default status list.
By default --cve-trackers is True.

Using --use-default-advisory without a value set for the matching key
in the build-data will cause an error and elliott will exit in a
non-zero state. Use of this option silently overrides providing an
advisory with the --add option.

    Automatically add bugs with target-release matching 3.7.Z or 3.7.0
    to advisory 123456:

\b
    $ elliott --group openshift-3.7 find-bugs --mode sweep --add 123456

    List bugs that WOULD be added to an advisory and have set the bro_ok flag on them (NOOP):

\b
    $ elliott --group openshift-3.7 find-bugs --mode sweep --flag bro_ok

    Attach bugs to their correct default advisories, e.g. operator-related bugs go to "extras" instead of the default "image":

\b
    $ elliott --group=openshift-4.4 find-bugs --mode=sweep --into-default-advisories

    Add two bugs to advisory 123456. Note that --group is not required
    because we're not auto searching:

\b
    $ elliott find-bugs --mode list --id 8675309 --id 7001337 --add 123456

    Automatically find bugs for openshift-4.1 and attach them to the
    rpm advisory defined in ocp-build-data:

\b
    $ elliott --group=openshift-4.1 --mode sweep --use-default-advisory rpm

    Find bugs for 4.6 that are in MODIFIED state, and set them to ON_QA:

\b
    $ elliott --group=openshift-4.6 --mode qe

\b
    $ elliott --group=openshift-4.6 --mode blocker --report
"""
    count_advisory_attach_flags = sum(
        map(bool, [advisory, default_advisory_type, into_default_advisories]))

    if mode != 'list' and len(id) > 0:
        raise click.BadParameter(
            "Combining the automatic and manual bug attachment options is not supported"
        )

    if mode == 'list' and len(id) == 0:
        raise click.BadParameter(
            "When using mode=list, you must provide a list of bug IDs")

    if mode == 'list' and into_default_advisories:
        raise click.BadParameter(
            "Cannot use --into-default-advisories with mode=list")

    if mode == 'diff' and not len(from_diff) == 2:
        raise click.BadParameter(
            "If using mode=diff, you must provide two payloads to compare")

    if count_advisory_attach_flags > 1:
        raise click.BadParameter(
            "Use only one of --use-default-advisory, --add, or --into-default-advisories"
        )

    if mode in ['qe', 'blocker'] and count_advisory_attach_flags > 0:
        raise click.BadParameter(
            "Mode does not operate on an advisory. Do not specify any of "
            "`--use-default-advisory`, `--add`, or `--into-default-advisories`"
        )

    runtime.initialize()
    bz_data = runtime.gitdata.load_data(key='bugzilla').data
    bzapi = bzutil.get_bzapi(bz_data)

    # filter out bugs ART does not manage
    m = re.match(
        r"rhaos-(\d+).(\d+)", runtime.branch
    )  # extract OpenShift version from the branch name. there should be a better way...
    if not m:
        raise ElliottFatalError(
            f"Unable to determine OpenShift version from branch name {runtime.branch}."
        )
    major_version = int(m[1])
    minor_version = int(m[2])

    if default_advisory_type is not None:
        advisory = find_default_advisory(runtime, default_advisory_type)

    if mode in ['sweep', 'qe', 'blocker']:
        if not cve_trackers:
            if mode == 'blocker':
                cve_trackers = True
            else:
                cve_trackers = False

        if not status:  # use default status filter according to mode
            if mode == 'sweep':
                status = ['MODIFIED', 'ON_QA', 'VERIFIED']
            if mode == 'qe':
                status = ['MODIFIED']
            if mode == 'blocker':
                status = [
                    'NEW', 'ASSIGNED', 'POST', 'MODIFIED', 'ON_DEV', 'ON_QA'
                ]

        if mode != 'qe' and exclude_status:
            status = set(status) - set(exclude_status)

        green_prefix(
            f"Searching for bugs with status {' '.join(status)} and target release(s):"
        )
        click.echo(" {tr}".format(tr=", ".join(bz_data['target_release'])))

        search_flag = 'blocker+' if mode == 'blocker' else None
        bugs = bzutil.search_for_bugs(
            bz_data,
            status,
            flag=search_flag,
            filter_out_security_bugs=not (cve_trackers),
            verbose=runtime.debug)
    elif mode == 'list':
        bugs = [bzapi.getbug(i) for i in cli_opts.id_convert(id)]
        mode_list(advisory=advisory,
                  bugs=bugs,
                  flags=flag,
                  report=report,
                  noop=noop)
        return
    elif mode == 'diff':
        click.echo(runtime.working_dir)
        bug_id_strings = openshiftclient.get_bug_list(runtime.working_dir,
                                                      from_diff[0],
                                                      from_diff[1])
        bugs = [bzapi.getbug(i) for i in bug_id_strings]

    filtered_bugs = filter_bugs(bugs, major_version, minor_version, runtime)
    green_prefix(
        f"Found {len(filtered_bugs)} bugs ({len(bugs) - len(filtered_bugs)} ignored): "
    )
    bugs = filtered_bugs
    click.echo(", ".join(sorted(str(b.bug_id) for b in bugs)))

    if mode == 'qe':
        for bug in bugs:
            bzutil.set_state(bug, 'ON_QA', noop=noop)

    if len(flag) > 0:
        add_flags(bugs=bugs, flags=flag, noop=noop)

    if report:
        print_report(bugs)

    if advisory and not default_advisory_type:  # `--add ADVISORY_NUMBER` should respect the user's wish and attach all available bugs to whatever advisory is specified.
        errata.add_bugs_with_retry(advisory, bugs, noop=noop)
        return

    # If --use-default-advisory or --into-default-advisories is given, we need to determine which bugs should be swept into which advisory.
    # Otherwise we don't need to sweep bugs at all.
    if not (into_default_advisories or default_advisory_type):
        return

    # key is impetus ("rpm", "image", "extras"), value is a set of bug IDs.
    impetus_bugs = {"rpm": set(), "image": set(), "extras": set()}

    # @lmeyer: simple and stupid would still be keeping the logic in python,
    # possibly with config flags for branched logic.
    # until that logic becomes too ugly to keep in python, i suppose..
    if major_version < 4:  # for 3.x, all bugs should go to the rpm advisory
        impetus_bugs["rpm"] = set(bugs)
    else:  # for 4.x
        # sweep rpm cve trackers into "rpm" advisory
        rpm_bugs = dict()
        if mode == 'sweep' and cve_trackers:
            rpm_bugs = bzutil.get_valid_rpm_cves(bugs)
            green_prefix("RPM CVEs found: ")
            click.echo(sorted(b.id for b in rpm_bugs))

            if rpm_bugs:
                # if --check-builds flag is set
                # only attach bugs that have corresponding brew builds attached to rpm advisory
                if check_builds:
                    click.echo(
                        "Validating bugs with builds attached to the rpm advisory"
                    )
                    attached_builds = errata.get_advisory_nvrs(
                        runtime.group_config.advisories["rpm"])
                    packages = attached_builds.keys()
                    not_found = []
                    for bug, package_name in rpm_bugs.items():
                        if package_name not in packages:
                            not_found.append((bug.id, package_name))
                        else:
                            click.echo(
                                f"Build found for #{bug.id}, {package_name}")
                            impetus_bugs["rpm"].add(bug)

                    if not_found:
                        red_prefix("RPM CVE Warning: ")
                        click.echo(
                            "The following CVE (bug, package) were found but not attached, because no corresponding brew builds were found attached to the rpm advisory. First attach builds and then rerun to attach the bugs"
                        )
                        click.echo(not_found)
                else:
                    click.echo(
                        "Skipping attaching RPM CVEs. Use --check-builds flag to validate with builds."
                    )

        # optional operators bugs should be swept to the "extras" advisory
        # a way to identify operator-related bugs is by its "Component" value.
        # temporarily hardcode here until we need to move it to ocp-build-data.
        extra_components = {
            "Logging", "Service Brokers", "Metering Operator",
            "Node Feature Discovery Operator"
        }  # we will probably find more
        impetus_bugs["extras"] = {
            b
            for b in bugs if b.component in extra_components
        }

        # all other bugs should go into "image" advisory
        impetus_bugs["image"] = set(
            bugs) - impetus_bugs["extras"] - rpm_bugs.keys()

    if default_advisory_type and impetus_bugs.get(default_advisory_type):
        errata.add_bugs_with_retry(advisory,
                                   impetus_bugs[default_advisory_type],
                                   noop=noop)
    elif into_default_advisories:
        for impetus, bugs in impetus_bugs.items():
            if bugs:
                green_prefix(f'{impetus} advisory: ')
                errata.add_bugs_with_retry(
                    runtime.group_config.advisories[impetus], bugs, noop=noop)
コード例 #9
0
def find_bugs(runtime, advisory, default_advisory_type, mode, status, id,
              from_diff, flag, report):
    """Find Red Hat Bugzilla bugs or add them to ADVISORY. Bugs can be
"swept" into the advisory either automatically (--mode sweep), or by
manually specifying one or more bugs using --mode list and the --id option.
Use cases are described below:

    Note: Using --id without --add is basically pointless

SWEEP: For this use-case the --group option MUST be provided. The
--group automatically determines the correct target-releases to search
for MODIFIED bugs in.

LIST: The --group option is not required if you are specifying bugs
manually. Provide one or more --id's for manual bug addition. In LIST
mode you must provide a list of IDs to attach with the --id option.

DIFF: For this use case, you must provide the --between option using two
URLs to payloads.

Using --use-default-advisory without a value set for the matching key
in the build-data will cause an error and elliott will exit in a
non-zero state. Use of this option silently overrides providing an
advisory with the --add option.

    Automatically add bugs with target-release matching 3.7.Z or 3.7.0
    to advisory 123456:

\b
    $ elliott --group openshift-3.7 find-bugs --mode sweep --add 123456

    List bugs that WOULD be added to an advisory and have set the bro_ok flag on them (NOOP):

\b
    $ elliott --group openshift-3.7 find-bugs --mode sweep --flag bro_ok

    Add two bugs to advisory 123456. Note that --group is not required
    because we're not auto searching:

\b
    $ elliott find-bugs --mode list --id 8675309 --id 7001337 --add 123456

    Automatically find bugs for openshift-4.1 and attach them to the
    rpm advisory defined in ocp-build-data:

\b
    $ elliott --group=openshift-4.1 --mode sweep --use-default-advisory rpm
"""
    if mode != 'list' and len(id) > 0:
        raise click.BadParameter(
            "Combining the automatic and manual bug attachment options is not supported"
        )

    if mode == 'list' and len(id) == 0:
        raise click.BadParameter(
            "When using mode=list, you must provide a list of bug IDs")

    if mode == 'payload' and not len(from_diff) == 2:
        raise click.BadParameter(
            "If using mode=payload, you must provide two payloads to compare")

    if advisory and default_advisory_type:
        raise click.BadParameter(
            "Use only one of --use-default-advisory or --add")

    runtime.initialize()
    bz_data = runtime.gitdata.load_data(key='bugzilla').data
    bzapi = elliottlib.bzutil.get_bzapi(bz_data)

    if default_advisory_type is not None:
        advisory = find_default_advisory(runtime, default_advisory_type)

    if mode == 'sweep':
        green_prefix("Searching for bugs with target release(s):")
        click.echo(" {tr}".format(tr=", ".join(bz_data['target_release'])))
        bug_ids = elliottlib.bzutil.search_for_bugs(bz_data,
                                                    status,
                                                    verbose=runtime.debug)
    elif mode == 'list':
        bug_ids = [bzapi.getbug(i) for i in cli_opts.id_convert(id)]
    elif mode == "diff":
        click.echo(runtime.working_dir)
        bug_id_strings = elliottlib.openshiftclient.get_bug_list(
            runtime.working_dir, from_diff[0], from_diff[1])
        bug_ids = [bzapi.getbug(i) for i in bug_id_strings]

    green_prefix("Found {} bugs:".format(len(bug_ids)))
    click.echo(" {}".format(", ".join([str(b.bug_id) for b in bug_ids])))

    if report:
        green_print("{:<8s} {:<25s} {:<12s} {:<7s} {:<10s} {:60s}".format(
            "ID", "COMPONENT", "STATUS", "SCORE", "AGE", "SUMMARY"))
        for bug in bug_ids:
            created_date = datetime.datetime.strptime(str(bug.creation_time),
                                                      '%Y%m%dT%H:%M:%S')
            days_ago = (datetime.datetime.today() - created_date).days
            click.echo(
                "{:<8d} {:<25s} {:<12s} {:<7s} {:<3d} days   {:60s} ".format(
                    bug.id, bug.component, bug.status,
                    bug.cf_pm_score if hasattr(bug, "cf_pm_score") else '?',
                    days_ago, bug.summary[:60]))

    if len(flag) > 0:
        for bug in bug_ids:
            for f in flag:
                bug.updateflags({f: "+"})

    if advisory is not False:
        elliottlib.errata.add_bugs_with_retry(advisory,
                                              [bug.id for bug in bug_ids],
                                              False)