tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

intermittents_mach_commands.py (5006B)


      1 # This Source Code Form is subject to the terms of the Mozilla Public
      2 # License, v. 2.0. If a copy of the MPL was not distributed with this
      3 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
      4 
      5 import json
      6 import logging
      7 import sys
      8 
      9 from intermittent_failures import IntermittentFailuresFetcher
     10 from mach.decorators import Command, CommandArgument, SubCommand
     11 
     12 
     13 @Command(
     14    "intermittents",
     15    category="testing",
     16    description="Analyze intermittent test failures",
     17 )
     18 def intermittents(command_context):
     19    """
     20    Utility to analyze intermittent test failures in Firefox.
     21    """
     22    # Print help text when no subcommand is provided
     23    print("usage: mach intermittents <subcommand> [options]")
     24    print()
     25    print("Analyze intermittent test failures in Firefox.")
     26    print()
     27    print("subcommands:")
     28    print("  list    List the most frequent intermittent test failures")
     29    print()
     30    print("Run 'mach intermittents <subcommand> --help' for more information.")
     31    sys.exit(0)
     32 
     33 
     34 @SubCommand(
     35    "intermittents",
     36    "list",
     37    description="List the most frequent intermittent test failures",
     38 )
     39 @CommandArgument(
     40    "--days",
     41    type=int,
     42    default=7,
     43    help="Number of days to look back for failures (default: 7)",
     44 )
     45 @CommandArgument(
     46    "--threshold",
     47    type=int,
     48    default=30,
     49    help="Minimum number of failures to include (default: 30)",
     50 )
     51 @CommandArgument(
     52    "--branch",
     53    default="trunk",
     54    help="Branch to query (default: trunk)",
     55 )
     56 @CommandArgument(
     57    "--json",
     58    action="store_true",
     59    dest="json_output",
     60    help="Output results as JSON",
     61 )
     62 @CommandArgument(
     63    "--verbose",
     64    action="store_true",
     65    help="Show additional details for each failure",
     66 )
     67 @CommandArgument(
     68    "--all",
     69    action="store_true",
     70    help="Show all bugs (by default only single tracking bugs with test paths are shown)",
     71 )
     72 def list_intermittents(
     73    command_context,
     74    days=7,
     75    threshold=30,
     76    branch="trunk",
     77    json_output=False,
     78    verbose=False,
     79    all=False,
     80 ):
     81    """List the most frequent intermittent test failures"""
     82 
     83    # Logging setup
     84    if not json_output:
     85        command_context.log(
     86            logging.INFO,
     87            "intermittents",
     88            {},
     89            f"Fetching intermittent failures from the last {days} days with at least {threshold} occurrences...",
     90        )
     91 
     92    fetcher = IntermittentFailuresFetcher(
     93        days=days, threshold=threshold, verbose=verbose and not json_output
     94    )
     95 
     96    try:
     97        results = fetcher.get_failures(branch=branch)
     98    except Exception as e:
     99        command_context.log(
    100            logging.ERROR,
    101            "intermittents",
    102            {"error": str(e)},
    103            "Error fetching failures: {error}",
    104        )
    105        return 1
    106 
    107    if not all:
    108        results = [
    109            result
    110            for result in results
    111            if result.get("test_path") and "single tracking bug" in result["summary"]
    112        ]
    113 
    114    if not results:
    115        if not json_output:
    116            message = f"No bugs found with at least {threshold} failures in the last {days} days."
    117            if not all:
    118                message = f"No single tracking bugs with test paths found with at least {threshold} failures in the last {days} days. Use --all to see all bugs."
    119            command_context.log(
    120                logging.INFO,
    121                "intermittents",
    122                {},
    123                message,
    124            )
    125        else:
    126            print(json.dumps([]))
    127        return 0
    128 
    129    results.sort(key=lambda x: x["failure_count"], reverse=True)
    130 
    131    if json_output:
    132        print(json.dumps(results, indent=2))
    133    else:
    134        command_context.log(
    135            logging.INFO,
    136            "intermittents",
    137            {"count": len(results), "threshold": threshold},
    138            "Found {count} bugs with at least {threshold} failures:",
    139        )
    140        print()
    141 
    142        for i, result in enumerate(results, 1):
    143            print(f"{i}. Bug {result['bug_id']}: {result['failure_count']} failures")
    144            if result.get("test_path"):
    145                print(f"   Test: {result['test_path']}")
    146            print(f"   Summary: {result['summary']}")
    147            print(f"   Status: {result['status']}", end="")
    148            if result.get("resolution"):
    149                print(f" - {result['resolution']}")
    150            else:
    151                print()
    152            if result.get("creation_time"):
    153                created = result["creation_time"].split("T")[0]  # Just the date part
    154                print(f"   Created: {created}")
    155            if result.get("last_change_time"):
    156                updated = result["last_change_time"].split("T")[0]  # Just the date part
    157                print(f"   Last updated: {updated}")
    158            if result.get("comment_count") is not None:
    159                print(f"   Comments: {result['comment_count']}")
    160            print(
    161                f"   URL: https://bugzilla.mozilla.org/show_bug.cgi?id={result['bug_id']}"
    162            )
    163            print()
    164 
    165    return 0