2024-12-17T23:28:39.1054014Z Current runner version: '2.321.0' 2024-12-17T23:28:39.1077815Z ##[group]Operating System 2024-12-17T23:28:39.1078660Z Ubuntu 2024-12-17T23:28:39.1079112Z 22.04.5 2024-12-17T23:28:39.1079710Z LTS 2024-12-17T23:28:39.1080196Z ##[endgroup] 2024-12-17T23:28:39.1080682Z ##[group]Runner Image 2024-12-17T23:28:39.1081337Z Image: ubuntu-22.04 2024-12-17T23:28:39.1081868Z Version: 20241215.1.0 2024-12-17T23:28:39.1082885Z Included Software: https://github.com/actions/runner-images/blob/ubuntu22/20241215.1/images/ubuntu/Ubuntu2204-Readme.md 2024-12-17T23:28:39.1084328Z Image Release: https://github.com/actions/runner-images/releases/tag/ubuntu22%2F20241215.1 2024-12-17T23:28:39.1085227Z ##[endgroup] 2024-12-17T23:28:39.1085715Z ##[group]Runner Image Provisioner 2024-12-17T23:28:39.1086378Z 2.0.404.1 2024-12-17T23:28:39.1086844Z ##[endgroup] 2024-12-17T23:28:39.1089405Z ##[group]GITHUB_TOKEN Permissions 2024-12-17T23:28:39.1091341Z Actions: read 2024-12-17T23:28:39.1092177Z Attestations: read 2024-12-17T23:28:39.1092796Z Checks: read 2024-12-17T23:28:39.1093242Z Contents: read 2024-12-17T23:28:39.1093800Z Deployments: read 2024-12-17T23:28:39.1094326Z Discussions: read 2024-12-17T23:28:39.1094809Z Issues: read 2024-12-17T23:28:39.1095362Z Metadata: read 2024-12-17T23:28:39.1095864Z Packages: read 2024-12-17T23:28:39.1096333Z Pages: read 2024-12-17T23:28:39.1096856Z PullRequests: read 2024-12-17T23:28:39.1097398Z RepositoryProjects: read 2024-12-17T23:28:39.1097930Z SecurityEvents: read 2024-12-17T23:28:39.1098489Z Statuses: read 2024-12-17T23:28:39.1098983Z ##[endgroup] 2024-12-17T23:28:39.1101878Z Secret source: Actions 2024-12-17T23:28:39.1102714Z Prepare workflow directory 2024-12-17T23:28:39.1584777Z Prepare all required actions 2024-12-17T23:28:39.1638670Z Uses: pytorch/pytorch/.github/workflows/_runner-determinator.yml@refs/heads/release/2.6 (0cdf8b1d09254cfda66191d1bd01e3041c3c76f7) 2024-12-17T23:28:39.1643655Z ##[group] Inputs 2024-12-17T23:28:39.1644248Z check_experiments: 2024-12-17T23:28:39.1644968Z triggering_actor: malfet 2024-12-17T23:28:39.1645581Z issue_owner: 2024-12-17T23:28:39.1646065Z curr_branch: release/2.6 2024-12-17T23:28:39.1646711Z curr_ref_type: branch 2024-12-17T23:28:39.1647251Z issue_number: 5132 2024-12-17T23:28:39.1648418Z ##[endgroup] 2024-12-17T23:28:39.1649149Z Complete job name: get-label-type / runner-determinator 2024-12-17T23:28:39.2340927Z ##[group]Run cat < runner_determinator.py 2024-12-17T23:28:39.2343399Z cat < runner_determinator.py 2024-12-17T23:28:39.2344165Z # flake8: noqa: G004 2024-12-17T23:28:39.2344748Z  2024-12-17T23:28:39.2345459Z # Note: Copies of this script in runner_determinator.py and _runner-determinator.yml 2024-12-17T23:28:39.2346601Z # must be kept in sync. You can do it easily by running the following command: 2024-12-17T23:28:39.2347553Z # python .github/scripts/update_runner_determinator.py 2024-12-17T23:28:39.2348229Z  2024-12-17T23:28:39.2348759Z """ 2024-12-17T23:28:39.2349487Z This runner determinator is used to determine which set of runners to run a 2024-12-17T23:28:39.2350469Z GitHub job on. It uses the first comment of a GitHub issue (by default 2024-12-17T23:28:39.2351697Z https://github.com/pytorch/test-infra/issues/5132) to define the configuration 2024-12-17T23:28:39.2352628Z of which runners should be used to run which job. 2024-12-17T23:28:39.2353316Z  2024-12-17T23:28:39.2354097Z The configuration has two parts, the settings and a list of opted-in users, 2024-12-17T23:28:39.2355133Z separated by a line containing "---". If the line is not present, the 2024-12-17T23:28:39.2356109Z settings are considered to be empty with only the second part, the user 2024-12-17T23:28:39.2357017Z list, defined. 2024-12-17T23:28:39.2357543Z  2024-12-17T23:28:39.2358157Z The first part is a YAML block that defines the rollout settings. This can be 2024-12-17T23:28:39.2360273Z used to define any settings that are needed to determine which runners to use. 2024-12-17T23:28:39.2362000Z It's fields are defined by the RolloutSettings class below. 2024-12-17T23:28:39.2362835Z  2024-12-17T23:28:39.2363543Z The second part is a list of users who are explicitly opted in to the LF fleet. 2024-12-17T23:28:39.2364595Z The user list is also a comma separated list of additional features or 2024-12-17T23:28:39.2365526Z experiments which the user could be opted in to. 2024-12-17T23:28:39.2366182Z  2024-12-17T23:28:39.2366694Z The user list has the following rules: 2024-12-17T23:28:39.2367656Z  2024-12-17T23:28:39.2368348Z - Users are GitHub usernames, which must start with the @ prefix 2024-12-17T23:28:39.2369339Z - Each user is also a comma-separated list of features/experiments to enable 2024-12-17T23:28:39.2370308Z - A "#" prefix opts the user out of all experiments 2024-12-17T23:28:39.2371016Z  2024-12-17T23:28:39.2371460Z Example config: 2024-12-17T23:28:39.2372133Z  # A list of experiments that can be opted into. 2024-12-17T23:28:39.2372977Z  # This defines the behavior they'll induce when opted into. 2024-12-17T23:28:39.2373719Z  # Expected syntax is: 2024-12-17T23:28:39.2374583Z  # [experiment_name]: # Name of the experiment. Also used for the label prefix. 2024-12-17T23:28:39.2375728Z  # rollout_perc: [int] # % of workflows to run with this experiment when users are not opted in. 2024-12-17T23:28:39.2376566Z  2024-12-17T23:28:39.2377082Z  experiments: 2024-12-17T23:28:39.2377642Z  lf: 2024-12-17T23:28:39.2378114Z  rollout_percent: 25 2024-12-17T23:28:39.2378791Z  all_branches: false 2024-12-17T23:28:39.2379386Z  default: true 2024-12-17T23:28:39.2379903Z  --- 2024-12-17T23:28:39.2380435Z  2024-12-17T23:28:39.2380910Z  # Opt-ins: 2024-12-17T23:28:39.2381658Z  # Users can opt into the LF fleet by adding their GitHub username to this list 2024-12-17T23:28:39.2383554Z  # and specifying experiments to enable in a comma-separated list. 2024-12-17T23:28:39.2385139Z  # To always opt out of an experiment, prefix it with a "-". 2024-12-17T23:28:39.2386568Z  # Experiments should be from the above list. 2024-12-17T23:28:39.2387402Z  2024-12-17T23:28:39.2387999Z  @User1,-lf,split_build 2024-12-17T23:28:39.2388593Z  @User2,lf 2024-12-17T23:28:39.2389216Z  @User3,split_build 2024-12-17T23:28:39.2389736Z """ 2024-12-17T23:28:39.2390197Z  2024-12-17T23:28:39.2390738Z import json 2024-12-17T23:28:39.2391230Z import logging 2024-12-17T23:28:39.2391749Z import os 2024-12-17T23:28:39.2392339Z import random 2024-12-17T23:28:39.2392880Z import re 2024-12-17T23:28:39.2393363Z import sys 2024-12-17T23:28:39.2393980Z from argparse import ArgumentParser 2024-12-17T23:28:39.2394621Z from functools import lru_cache 2024-12-17T23:28:39.2395239Z from logging import LogRecord 2024-12-17T23:28:39.2396173Z from typing import Any, Dict, FrozenSet, Iterable, List, NamedTuple, Set, Tuple 2024-12-17T23:28:39.2397079Z from urllib.request import Request, urlopen 2024-12-17T23:28:39.2397709Z  2024-12-17T23:28:39.2398249Z import yaml 2024-12-17T23:28:39.2398781Z from github import Auth, Github 2024-12-17T23:28:39.2399391Z from github.Issue import Issue 2024-12-17T23:28:39.2400079Z  2024-12-17T23:28:39.2400483Z  2024-12-17T23:28:39.2400998Z DEFAULT_LABEL_PREFIX = "" # use meta runners 2024-12-17T23:28:39.2402157Z WORKFLOW_LABEL_LF = "lf." # use runners from the linux foundation 2024-12-17T23:28:39.2403161Z WORKFLOW_LABEL_LF_CANARY = "lf.c." # use canary runners from the linux foundation 2024-12-17T23:28:39.2403925Z  2024-12-17T23:28:39.2404560Z GITHUB_OUTPUT = os.getenv("GITHUB_OUTPUT", "") 2024-12-17T23:28:39.2405305Z GH_OUTPUT_KEY_AMI = "runner-ami" 2024-12-17T23:28:39.2405911Z GH_OUTPUT_KEY_LABEL_TYPE = "label-type" 2024-12-17T23:28:39.2406736Z OPT_OUT_LABEL = "no-runner-experiments" 2024-12-17T23:28:39.2407693Z  2024-12-17T23:28:39.2408229Z SETTING_EXPERIMENTS = "experiments" 2024-12-17T23:28:39.2409536Z  2024-12-17T23:28:39.2410309Z LF_FLEET_EXPERIMENT = "lf" 2024-12-17T23:28:39.2411212Z CANARY_FLEET_SUFFIX = ".c" 2024-12-17T23:28:39.2411929Z  2024-12-17T23:28:39.2412366Z  2024-12-17T23:28:39.2412824Z class Experiment(NamedTuple): 2024-12-17T23:28:39.2413545Z  rollout_perc: float = ( 2024-12-17T23:28:39.2414359Z  0 # Percentage of workflows to experiment on when user is not opted-in. 2024-12-17T23:28:39.2415131Z  ) 2024-12-17T23:28:39.2415733Z  all_branches: bool = ( 2024-12-17T23:28:39.2416545Z  False # If True, the experiment is also enabled on the exception branches 2024-12-17T23:28:39.2417280Z  ) 2024-12-17T23:28:39.2417846Z  default: bool = ( 2024-12-17T23:28:39.2418590Z  True # If True, the experiment is enabled by default for all queries 2024-12-17T23:28:39.2419389Z  ) 2024-12-17T23:28:39.2419832Z  2024-12-17T23:28:39.2420314Z  # Add more fields as needed 2024-12-17T23:28:39.2420965Z  2024-12-17T23:28:39.2421383Z  2024-12-17T23:28:39.2421870Z class Settings(NamedTuple): 2024-12-17T23:28:39.2422497Z  """ 2024-12-17T23:28:39.2423096Z  Settings for the experiments that can be opted into. 2024-12-17T23:28:39.2423808Z  """ 2024-12-17T23:28:39.2424694Z  2024-12-17T23:28:39.2425220Z  experiments: Dict[str, Experiment] = {} 2024-12-17T23:28:39.2425852Z  2024-12-17T23:28:39.2426371Z  2024-12-17T23:28:39.2427066Z class ColorFormatter(logging.Formatter): 2024-12-17T23:28:39.2427885Z  """Color codes the log messages based on the log level""" 2024-12-17T23:28:39.2428645Z  2024-12-17T23:28:39.2429079Z  COLORS = { 2024-12-17T23:28:39.2429645Z  "WARNING": "\033[33m", # Yellow 2024-12-17T23:28:39.2430334Z  "ERROR": "\033[31m", # Red 2024-12-17T23:28:39.2430934Z  "CRITICAL": "\033[31m", # Red 2024-12-17T23:28:39.2431585Z  "INFO": "\033[0m", # Reset 2024-12-17T23:28:39.2432251Z  "DEBUG": "\033[0m", # Reset 2024-12-17T23:28:39.2432879Z  } 2024-12-17T23:28:39.2433418Z  2024-12-17T23:28:39.2434050Z  def format(self, record: LogRecord) -> str: 2024-12-17T23:28:39.2434936Z  log_color = self.COLORS.get(record.levelname, "\033[0m") # Default to reset 2024-12-17T23:28:39.2435863Z  record.msg = f"{log_color}{record.msg}\033[0m" 2024-12-17T23:28:39.2436616Z  return super().format(record) 2024-12-17T23:28:39.2437305Z  2024-12-17T23:28:39.2437762Z  2024-12-17T23:28:39.2438329Z handler = logging.StreamHandler() 2024-12-17T23:28:39.2439236Z handler.setFormatter(ColorFormatter(fmt="%(levelname)-8s: %(message)s")) 2024-12-17T23:28:39.2440084Z  2024-12-17T23:28:39.2440753Z log = logging.getLogger(os.path.basename(__file__)) 2024-12-17T23:28:39.2441497Z log.addHandler(handler) 2024-12-17T23:28:39.2442057Z log.setLevel(logging.INFO) 2024-12-17T23:28:39.2442681Z  2024-12-17T23:28:39.2443318Z  2024-12-17T23:28:39.2443854Z def set_github_output(key: str, value: str) -> None: 2024-12-17T23:28:39.2444613Z  """ 2024-12-17T23:28:39.2445282Z  Defines outputs of the github action that invokes this script 2024-12-17T23:28:39.2446004Z  """ 2024-12-17T23:28:39.2446561Z  if not GITHUB_OUTPUT: 2024-12-17T23:28:39.2448181Z  # See https://github.blog/changelog/2022-10-11-github-actions-deprecating-save-state-and-set-output-commands/ for deprecation notice 2024-12-17T23:28:39.2449391Z  log.warning( 2024-12-17T23:28:39.2450474Z  "No env var found for GITHUB_OUTPUT, you must be running this code locally. Falling back to the deprecated print method." 2024-12-17T23:28:39.2451516Z  ) 2024-12-17T23:28:39.2452314Z  print(f"::set-output name={key}::{value}") 2024-12-17T23:28:39.2453451Z  return 2024-12-17T23:28:39.2454287Z  2024-12-17T23:28:39.2455100Z  with open(GITHUB_OUTPUT, "a") as f: 2024-12-17T23:28:39.2456260Z  log.info(f"Setting output: {key}='{value}'") 2024-12-17T23:28:39.2457437Z  f.write(f"{key}={value}\n") 2024-12-17T23:28:39.2458481Z  2024-12-17T23:28:39.2459219Z  2024-12-17T23:28:39.2460249Z def _str_comma_separated_to_set(value: str) -> FrozenSet[str]: 2024-12-17T23:28:39.2461575Z  return frozenset( 2024-12-17T23:28:39.2462865Z  filter(lambda itm: itm != "", map(str.strip, value.strip(" \n\t").split(","))) 2024-12-17T23:28:39.2464243Z  ) 2024-12-17T23:28:39.2465025Z  2024-12-17T23:28:39.2465757Z  2024-12-17T23:28:39.2466564Z def parse_args() -> Any: 2024-12-17T23:28:39.2467847Z  parser = ArgumentParser("Get dynamic rollout settings") 2024-12-17T23:28:39.2469644Z  parser.add_argument("--github-token", type=str, required=True, help="GitHub token") 2024-12-17T23:28:39.2471131Z  parser.add_argument( 2024-12-17T23:28:39.2472094Z  "--github-issue-repo", 2024-12-17T23:28:39.2473175Z  type=str, 2024-12-17T23:28:39.2474022Z  required=False, 2024-12-17T23:28:39.2475277Z  default="pytorch/test-infra", 2024-12-17T23:28:39.2476556Z  help="GitHub repo to get the issue", 2024-12-17T23:28:39.2477520Z  ) 2024-12-17T23:28:39.2478285Z  parser.add_argument( 2024-12-17T23:28:39.2479317Z  "--github-repo", 2024-12-17T23:28:39.2480316Z  type=str, 2024-12-17T23:28:39.2481112Z  required=True, 2024-12-17T23:28:39.2481761Z  help="GitHub repo where CI is running", 2024-12-17T23:28:39.2482395Z  ) 2024-12-17T23:28:39.2482987Z  parser.add_argument( 2024-12-17T23:28:39.2483725Z  "--github-issue", type=int, required=True, help="GitHub issue number" 2024-12-17T23:28:39.2484506Z  ) 2024-12-17T23:28:39.2485082Z  parser.add_argument( 2024-12-17T23:28:39.2485828Z  "--github-actor", type=str, required=True, help="GitHub triggering_actor" 2024-12-17T23:28:39.2486716Z  ) 2024-12-17T23:28:39.2487208Z  parser.add_argument( 2024-12-17T23:28:39.2488450Z  "--github-issue-owner", type=str, required=True, help="GitHub issue owner" 2024-12-17T23:28:39.2489404Z  ) 2024-12-17T23:28:39.2489891Z  parser.add_argument( 2024-12-17T23:28:39.2490719Z  "--github-branch", type=str, required=True, help="Current GitHub branch or tag" 2024-12-17T23:28:39.2491609Z  ) 2024-12-17T23:28:39.2492075Z  parser.add_argument( 2024-12-17T23:28:39.2492666Z  "--github-ref-type", 2024-12-17T23:28:39.2493339Z  type=str, 2024-12-17T23:28:39.2494129Z  required=True, 2024-12-17T23:28:39.2494778Z  help="Current GitHub ref type, branch or tag", 2024-12-17T23:28:39.2495511Z  ) 2024-12-17T23:28:39.2495986Z  parser.add_argument( 2024-12-17T23:28:39.2496639Z  "--eligible-experiments", 2024-12-17T23:28:39.2497390Z  type=_str_comma_separated_to_set, 2024-12-17T23:28:39.2498062Z  required=False, 2024-12-17T23:28:39.2498667Z  default="", 2024-12-17T23:28:39.2499732Z  help="comma separated list of experiments to check, if omitted all experiments marked with default=True are checked", 2024-12-17T23:28:39.2500783Z  ) 2024-12-17T23:28:39.2501249Z  parser.add_argument( 2024-12-17T23:28:39.2501886Z  "--pr-number", 2024-12-17T23:28:39.2502461Z  type=str, 2024-12-17T23:28:39.2502980Z  required=False, 2024-12-17T23:28:39.2503580Z  default="", 2024-12-17T23:28:39.2504247Z  help="the optional PR number where this is run", 2024-12-17T23:28:39.2504880Z  ) 2024-12-17T23:28:39.2505382Z  2024-12-17T23:28:39.2505903Z  return parser.parse_args() 2024-12-17T23:28:39.2506461Z  2024-12-17T23:28:39.2506946Z  2024-12-17T23:28:39.2507523Z def get_gh_client(github_token: str) -> Github: 2024-12-17T23:28:39.2508187Z  auth = Auth.Token(github_token) 2024-12-17T23:28:39.2508863Z  return Github(auth=auth) 2024-12-17T23:28:39.2509467Z  2024-12-17T23:28:39.2509869Z  2024-12-17T23:28:39.2510520Z def get_issue(gh: Github, repo: str, issue_num: int) -> Issue: 2024-12-17T23:28:39.2511322Z  repo = gh.get_repo(repo) 2024-12-17T23:28:39.2511932Z  return repo.get_issue(number=issue_num) 2024-12-17T23:28:39.2512603Z  2024-12-17T23:28:39.2513091Z  2024-12-17T23:28:39.2513527Z def get_potential_pr_author( 2024-12-17T23:28:39.2514371Z  github_token: str, repo: str, username: str, ref_type: str, ref_name: str 2024-12-17T23:28:39.2515196Z ) -> str: 2024-12-17T23:28:39.2515819Z  # If the trigger was a new tag added by a bot, this is a ciflow case 2024-12-17T23:28:39.2517057Z  # Fetch the actual username from the original PR. The PR number is 2024-12-17T23:28:39.2518096Z  # embedded in the tag name: ciflow// 2024-12-17T23:28:39.2518815Z  2024-12-17T23:28:39.2519337Z  gh = get_gh_client(github_token) 2024-12-17T23:28:39.2520461Z  2024-12-17T23:28:39.2521428Z  if username == "pytorch-bot[bot]" and ref_type == "tag": 2024-12-17T23:28:39.2522668Z  split_tag = ref_name.split("/") 2024-12-17T23:28:39.2523581Z  if ( 2024-12-17T23:28:39.2524574Z  len(split_tag) == 3 2024-12-17T23:28:39.2525579Z  and split_tag[0] == "ciflow" 2024-12-17T23:28:39.2526555Z  and split_tag[2].isnumeric() 2024-12-17T23:28:39.2527832Z  ): 2024-12-17T23:28:39.2528552Z  pr_number = split_tag[2] 2024-12-17T23:28:39.2529133Z  try: 2024-12-17T23:28:39.2529835Z  repository = gh.get_repo(repo) 2024-12-17T23:28:39.2530605Z  pull = repository.get_pull(number=int(pr_number)) 2024-12-17T23:28:39.2531318Z  except Exception as e: 2024-12-17T23:28:39.2532066Z  raise Exception( # noqa: TRY002 2024-12-17T23:28:39.2532881Z  f"issue with pull request {pr_number} from repo {repository}" 2024-12-17T23:28:39.2533643Z  ) from e 2024-12-17T23:28:39.2534281Z  return pull.user.login 2024-12-17T23:28:39.2535005Z  # In all other cases, return the original input username 2024-12-17T23:28:39.2535953Z  return username 2024-12-17T23:28:39.2536536Z  2024-12-17T23:28:39.2536992Z  2024-12-17T23:28:39.2537506Z def is_exception_branch(branch: str) -> bool: 2024-12-17T23:28:39.2538192Z  """ 2024-12-17T23:28:39.2539003Z  Branches that get opted out of experiments by default, until they're explicitly enabled. 2024-12-17T23:28:39.2539943Z  """ 2024-12-17T23:28:39.2540841Z  return branch.split("/")[0] in {"main", "nightly", "release", "landchecks"} 2024-12-17T23:28:39.2541761Z  2024-12-17T23:28:39.2542244Z  2024-12-17T23:28:39.2542806Z def load_yaml(yaml_text: str) -> Any: 2024-12-17T23:28:39.2543440Z  try: 2024-12-17T23:28:39.2543944Z  data = yaml.safe_load(yaml_text) 2024-12-17T23:28:39.2544611Z  return data 2024-12-17T23:28:39.2545183Z  except yaml.YAMLError: 2024-12-17T23:28:39.2545811Z  log.exception("Error loading YAML") 2024-12-17T23:28:39.2546505Z  raise 2024-12-17T23:28:39.2547027Z  2024-12-17T23:28:39.2547446Z  2024-12-17T23:28:39.2548247Z def extract_settings_user_opt_in_from_text(rollout_state: str) -> Tuple[str, str]: 2024-12-17T23:28:39.2549101Z  """ 2024-12-17T23:28:39.2549835Z  Extracts the text with settings, if any, and the opted in users from the rollout state. 2024-12-17T23:28:39.2550781Z  2024-12-17T23:28:39.2551392Z  If the issue body contains "---" then the text above that is the settings 2024-12-17T23:28:39.2552263Z  and the text below is the list of opted in users. 2024-12-17T23:28:39.2553022Z  2024-12-17T23:28:39.2553661Z  If it doesn't contain "---" then the settings are empty and the rest is the users. 2024-12-17T23:28:39.2554454Z  """ 2024-12-17T23:28:39.2555118Z  rollout_state_parts = rollout_state.split("---") 2024-12-17T23:28:39.2555801Z  if len(rollout_state_parts) >= 2: 2024-12-17T23:28:39.2556698Z  return rollout_state_parts[0], rollout_state_parts[1] 2024-12-17T23:28:39.2557569Z  else: 2024-12-17T23:28:39.2558608Z  return "", rollout_state 2024-12-17T23:28:39.2559554Z  2024-12-17T23:28:39.2560097Z  2024-12-17T23:28:39.2560562Z class UserOptins(Dict[str, List[str]]): 2024-12-17T23:28:39.2561191Z  """ 2024-12-17T23:28:39.2561923Z  Dictionary of users with a list of features they have opted into 2024-12-17T23:28:39.2562694Z  """ 2024-12-17T23:28:39.2563096Z  2024-12-17T23:28:39.2563609Z  2024-12-17T23:28:39.2564275Z def parse_user_opt_in_from_text(user_optin_text: str) -> UserOptins: 2024-12-17T23:28:39.2565006Z  """ 2024-12-17T23:28:39.2565920Z  Parse the user opt-in text into a key value pair of username and the list of features they have opted into 2024-12-17T23:28:39.2566895Z  2024-12-17T23:28:39.2568110Z  Users are GitHub usernames with the @ prefix. Each user is also a comma-separated list of features/experiments to enable. 2024-12-17T23:28:39.2569353Z  - Example line: "@User1,lf,split_build" 2024-12-17T23:28:39.2570180Z  - A "#" prefix indicates the user is opted out of all experiments 2024-12-17T23:28:39.2571090Z  2024-12-17T23:28:39.2571522Z  2024-12-17T23:28:39.2571950Z  """ 2024-12-17T23:28:39.2572472Z  optins = UserOptins() 2024-12-17T23:28:39.2573103Z  for user in user_optin_text.split("\n"): 2024-12-17T23:28:39.2573770Z  user = user.strip("\r\n\t -") 2024-12-17T23:28:39.2574512Z  if not user or not user.startswith("@"): 2024-12-17T23:28:39.2575177Z  # Not a valid user. Skip 2024-12-17T23:28:39.2575980Z  continue 2024-12-17T23:28:39.2576591Z  2024-12-17T23:28:39.2577015Z  if user: 2024-12-17T23:28:39.2577589Z  usr_name = user.split(",")[0].strip("@") 2024-12-17T23:28:39.2578473Z  optins[usr_name] = [exp.strip(" ") for exp in user.split(",")[1:]] 2024-12-17T23:28:39.2579196Z  2024-12-17T23:28:39.2579647Z  return optins 2024-12-17T23:28:39.2580227Z  2024-12-17T23:28:39.2580634Z  2024-12-17T23:28:39.2581250Z def is_valid_experiment_name(experiment_name: str) -> bool: 2024-12-17T23:28:39.2582041Z  """ 2024-12-17T23:28:39.2582547Z  Check if the experiment name is valid. 2024-12-17T23:28:39.2583185Z  A valid name: 2024-12-17T23:28:39.2584065Z  - Contains only alphanumeric characters and the special characters "_" & "-" 2024-12-17T23:28:39.2585140Z  - The special characters "_" & "-" shouldn't be the first or last characters 2024-12-17T23:28:39.2585944Z  - Cannot contain spaces 2024-12-17T23:28:39.2586569Z  """ 2024-12-17T23:28:39.2587036Z  2024-12-17T23:28:39.2587576Z  valid_char_regex = r"^[a-zA-Z0-9]([\w-]*[a-zA-Z0-9])?$" 2024-12-17T23:28:39.2588521Z  valid = bool(re.match(valid_char_regex, experiment_name)) 2024-12-17T23:28:39.2589247Z  2024-12-17T23:28:39.2589691Z  if valid: 2024-12-17T23:28:39.2590242Z  return True 2024-12-17T23:28:39.2590774Z  2024-12-17T23:28:39.2591195Z  log.error( 2024-12-17T23:28:39.2592800Z  f"Invalid experiment name: {experiment_name}. Experiment names should only contain alphanumeric characters, '_', and '-'. They cannot contain spaces, and the special characters '_' and '-' cannot be the first or last characters." 2024-12-17T23:28:39.2594447Z  ) 2024-12-17T23:28:39.2594888Z  return False 2024-12-17T23:28:39.2595438Z  2024-12-17T23:28:39.2595901Z  2024-12-17T23:28:39.2596484Z def parse_settings_from_text(settings_text: str) -> Settings: 2024-12-17T23:28:39.2597279Z  """ 2024-12-17T23:28:39.2598223Z  Parse the experiments from the issue body into a list of ExperimentSettings 2024-12-17T23:28:39.2599071Z  """ 2024-12-17T23:28:39.2599554Z  try: 2024-12-17T23:28:39.2600073Z  if settings_text: 2024-12-17T23:28:39.2600940Z  # Escape the backtick as well so that we can have the settings in a code block on the GH issue 2024-12-17T23:28:39.2601833Z  # for easy reading 2024-12-17T23:28:39.2602796Z  # Note: Using ascii for the backtick so that the cat step in _runner-determinator.yml doesn't choke on 2024-12-17T23:28:39.2603797Z  # the backtick character in shell commands. 2024-12-17T23:28:39.2604612Z  backtick = chr(96) # backtick character 2024-12-17T23:28:39.2605370Z  settings_text = settings_text.strip(f"\r\n\t{backtick} ") 2024-12-17T23:28:39.2606141Z  settings = load_yaml(settings_text) 2024-12-17T23:28:39.2606832Z  2024-12-17T23:28:39.2608156Z  # For now we just load experiments. We can expand this if/when we add more settings 2024-12-17T23:28:39.2609048Z  experiments = {} 2024-12-17T23:28:39.2609727Z  2024-12-17T23:28:39.2610356Z  for exp_name, exp_settings in settings.get(SETTING_EXPERIMENTS).items(): 2024-12-17T23:28:39.2611254Z  if not is_valid_experiment_name(exp_name): 2024-12-17T23:28:39.2612535Z  # Exclude invalid experiments from the list. We log an error, but don't raise an exception so that other experiments can still be processed. 2024-12-17T23:28:39.2613868Z  continue 2024-12-17T23:28:39.2614411Z  2024-12-17T23:28:39.2614954Z  valid_settings = {} 2024-12-17T23:28:39.2615605Z  for setting in exp_settings: 2024-12-17T23:28:39.2616258Z  if setting not in Experiment._fields: 2024-12-17T23:28:39.2617009Z  log.warning( 2024-12-17T23:28:39.2617867Z  f"Unexpected setting in experiment: {setting} = {exp_settings[setting]}" 2024-12-17T23:28:39.2618640Z  ) 2024-12-17T23:28:39.2619255Z  else: 2024-12-17T23:28:39.2619924Z  valid_settings[setting] = exp_settings[setting] 2024-12-17T23:28:39.2620593Z  2024-12-17T23:28:39.2621210Z  experiments[exp_name] = Experiment(**valid_settings) 2024-12-17T23:28:39.2621977Z  return Settings(experiments) 2024-12-17T23:28:39.2622576Z  2024-12-17T23:28:39.2623066Z  except Exception: 2024-12-17T23:28:39.2623706Z  log.exception("Failed to parse settings") 2024-12-17T23:28:39.2624334Z  2024-12-17T23:28:39.2624833Z  return Settings() 2024-12-17T23:28:39.2625385Z  2024-12-17T23:28:39.2625791Z  2024-12-17T23:28:39.2626410Z def parse_settings(rollout_state: str) -> Settings: 2024-12-17T23:28:39.2627096Z  """ 2024-12-17T23:28:39.2627636Z  Parse settings, if any, from the rollout state. 2024-12-17T23:28:39.2628342Z  2024-12-17T23:28:39.2628982Z  If the issue body contains "---" then the text above that is the settings 2024-12-17T23:28:39.2629857Z  and the text below is the list of opted in users. 2024-12-17T23:28:39.2630568Z  2024-12-17T23:28:39.2631270Z  If it doesn't contain "---" then the settings are empty and the default values are used. 2024-12-17T23:28:39.2632091Z  """ 2024-12-17T23:28:39.2632899Z  settings_text, _ = extract_settings_user_opt_in_from_text(rollout_state) 2024-12-17T23:28:39.2634270Z  return parse_settings_from_text(settings_text) 2024-12-17T23:28:39.2635285Z  2024-12-17T23:28:39.2636097Z  2024-12-17T23:28:39.2636689Z def parse_users(rollout_state: str) -> UserOptins: 2024-12-17T23:28:39.2637460Z  """ 2024-12-17T23:28:39.2637993Z  Parse users from the rollout state. 2024-12-17T23:28:39.2638573Z  2024-12-17T23:28:39.2639082Z  """ 2024-12-17T23:28:39.2639763Z  _, users_text = extract_settings_user_opt_in_from_text(rollout_state) 2024-12-17T23:28:39.2640588Z  return parse_user_opt_in_from_text(users_text) 2024-12-17T23:28:39.2641313Z  2024-12-17T23:28:39.2641757Z  2024-12-17T23:28:39.2642460Z def is_user_opted_in(user: str, user_optins: UserOptins, experiment_name: str) -> bool: 2024-12-17T23:28:39.2643372Z  """ 2024-12-17T23:28:39.2643930Z  Check if a user is opted into an experiment 2024-12-17T23:28:39.2644553Z  """ 2024-12-17T23:28:39.2645197Z  return experiment_name in user_optins.get(user, []) 2024-12-17T23:28:39.2645897Z  2024-12-17T23:28:39.2646305Z  2024-12-17T23:28:39.2647082Z def is_user_opted_out(user: str, user_optins: UserOptins, experiment_name: str) -> bool: 2024-12-17T23:28:39.2648463Z  """ 2024-12-17T23:28:39.2649100Z  Check if a user explicitly opted out of an experiment 2024-12-17T23:28:39.2649817Z  """ 2024-12-17T23:28:39.2650486Z  # if the experiment is prefixed with a "-", then it's an opt-out 2024-12-17T23:28:39.2651294Z  experiment_optout = "-" + experiment_name 2024-12-17T23:28:39.2652063Z  if experiment_optout not in user_optins.get(user, []): 2024-12-17T23:28:39.2652991Z  return False 2024-12-17T23:28:39.2653510Z  2024-12-17T23:28:39.2654091Z  if is_user_opted_in(user, user_optins, experiment_name): 2024-12-17T23:28:39.2654836Z  log.warning( 2024-12-17T23:28:39.2655784Z  f"User {user} is opted into experiment {experiment_name}, but also opted out of it. Defaulting to opting out" 2024-12-17T23:28:39.2656757Z  ) 2024-12-17T23:28:39.2657258Z  2024-12-17T23:28:39.2657707Z  return True 2024-12-17T23:28:39.2658214Z  2024-12-17T23:28:39.2658674Z  2024-12-17T23:28:39.2659132Z def get_runner_prefix( 2024-12-17T23:28:39.2659716Z  rollout_state: str, 2024-12-17T23:28:39.2660337Z  workflow_requestors: Iterable[str], 2024-12-17T23:28:39.2661007Z  branch: str, 2024-12-17T23:28:39.2661714Z  eligible_experiments: FrozenSet[str] = frozenset(), 2024-12-17T23:28:39.2662393Z  is_canary: bool = False, 2024-12-17T23:28:39.2662958Z ) -> str: 2024-12-17T23:28:39.2663581Z  settings = parse_settings(rollout_state) 2024-12-17T23:28:39.2664244Z  user_optins = parse_users(rollout_state) 2024-12-17T23:28:39.2664898Z  2024-12-17T23:28:39.2665415Z  fleet_prefix = "" 2024-12-17T23:28:39.2665934Z  prefixes = [] 2024-12-17T23:28:39.2666721Z  for experiment_name, experiment_settings in settings.experiments.items(): 2024-12-17T23:28:39.2667834Z  if not experiment_settings.all_branches and is_exception_branch(branch): 2024-12-17T23:28:39.2668608Z  log.info( 2024-12-17T23:28:39.2669462Z  f"Branch {branch} is an exception branch. Not enabling experiment {experiment_name}." 2024-12-17T23:28:39.2670360Z  ) 2024-12-17T23:28:39.2670870Z  continue 2024-12-17T23:28:39.2671389Z  2024-12-17T23:28:39.2671931Z  if eligible_experiments: 2024-12-17T23:28:39.2672651Z  if experiment_name not in eligible_experiments: 2024-12-17T23:28:39.2673350Z  exp_list = ", ".join(eligible_experiments) 2024-12-17T23:28:39.2674229Z  log.info( 2024-12-17T23:28:39.2675190Z  f"Skipping experiment '{experiment_name}', as it is not in the eligible_experiments list: {exp_list}" 2024-12-17T23:28:39.2676069Z  ) 2024-12-17T23:28:39.2676702Z  continue 2024-12-17T23:28:39.2677314Z  elif not experiment_settings.default: 2024-12-17T23:28:39.2677890Z  log.info( 2024-12-17T23:28:39.2678780Z  f"Skipping experiment '{experiment_name}', as it is not a default experiment" 2024-12-17T23:28:39.2679606Z  ) 2024-12-17T23:28:39.2680157Z  continue 2024-12-17T23:28:39.2680682Z  2024-12-17T23:28:39.2681251Z  # Is any workflow_requestor opted out to this experiment? 2024-12-17T23:28:39.2682015Z  opted_out_users = [ 2024-12-17T23:28:39.2682580Z  requestor 2024-12-17T23:28:39.2683174Z  for requestor in workflow_requestors 2024-12-17T23:28:39.2684011Z  if is_user_opted_out(requestor, user_optins, experiment_name) 2024-12-17T23:28:39.2684734Z  ] 2024-12-17T23:28:39.2685198Z  2024-12-17T23:28:39.2685718Z  if opted_out_users: 2024-12-17T23:28:39.2686277Z  log.info( 2024-12-17T23:28:39.2687030Z  f"{', '.join(opted_out_users)} have opted out of experiment {experiment_name}." 2024-12-17T23:28:39.2688222Z  ) 2024-12-17T23:28:39.2688725Z  continue 2024-12-17T23:28:39.2689242Z  2024-12-17T23:28:39.2690069Z  # Is any workflow_requestor opted in to this experiment? 2024-12-17T23:28:39.2690761Z  opted_in_users = [ 2024-12-17T23:28:39.2691339Z  requestor 2024-12-17T23:28:39.2691985Z  for requestor in workflow_requestors 2024-12-17T23:28:39.2692784Z  if is_user_opted_in(requestor, user_optins, experiment_name) 2024-12-17T23:28:39.2693491Z  ] 2024-12-17T23:28:39.2694014Z  2024-12-17T23:28:39.2694472Z  enabled = False 2024-12-17T23:28:39.2695013Z  if opted_in_users: 2024-12-17T23:28:39.2695621Z  log.info( 2024-12-17T23:28:39.2696392Z  f"{', '.join(opted_in_users)} have opted into experiment {experiment_name}." 2024-12-17T23:28:39.2697152Z  ) 2024-12-17T23:28:39.2697703Z  enabled = True 2024-12-17T23:28:39.2698290Z  2024-12-17T23:28:39.2698786Z  elif experiment_settings.rollout_perc: 2024-12-17T23:28:39.2699765Z  # If no user is opted in, then we randomly enable the experiment based on the rollout percentage 2024-12-17T23:28:39.2700849Z  if random.uniform(0, 100) <= experiment_settings.rollout_perc: 2024-12-17T23:28:39.2701558Z  log.info( 2024-12-17T23:28:39.2702595Z  f"Based on rollout percentage of {experiment_settings.rollout_perc}%, enabling experiment {experiment_name}." 2024-12-17T23:28:39.2703641Z  ) 2024-12-17T23:28:39.2704166Z  enabled = True 2024-12-17T23:28:39.2704843Z  2024-12-17T23:28:39.2705313Z  if enabled: 2024-12-17T23:28:39.2705873Z  label = experiment_name 2024-12-17T23:28:39.2706552Z  if experiment_name == LF_FLEET_EXPERIMENT: 2024-12-17T23:28:39.2707531Z  # We give some special treatment to the "lf" experiment since determines the fleet we use 2024-12-17T23:28:39.2708517Z  # - If it's enabled, then we always list it's prefix first 2024-12-17T23:28:39.2709612Z  # - If we're in the canary branch, then we append ".c" to the lf prefix 2024-12-17T23:28:39.2710359Z  if is_canary: 2024-12-17T23:28:39.2710970Z  label += CANARY_FLEET_SUFFIX 2024-12-17T23:28:39.2711698Z  fleet_prefix = label 2024-12-17T23:28:39.2712262Z  else: 2024-12-17T23:28:39.2712845Z  prefixes.append(label) 2024-12-17T23:28:39.2713522Z  2024-12-17T23:28:39.2713938Z  if len(prefixes) > 1: 2024-12-17T23:28:39.2714519Z  log.error( 2024-12-17T23:28:39.2715733Z  f"Only a fleet and one other experiment can be enabled for a job at any time. Enabling {prefixes[0]} and ignoring the rest, which are {', '.join(prefixes[1:])}" 2024-12-17T23:28:39.2716905Z  ) 2024-12-17T23:28:39.2717426Z  prefixes = prefixes[:1] 2024-12-17T23:28:39.2718057Z  2024-12-17T23:28:39.2718518Z  # Fleet always comes first 2024-12-17T23:28:39.2719095Z  if fleet_prefix: 2024-12-17T23:28:39.2719731Z  prefixes.insert(0, fleet_prefix) 2024-12-17T23:28:39.2720326Z  2024-12-17T23:28:39.2720875Z  return ".".join(prefixes) + "." if prefixes else "" 2024-12-17T23:28:39.2721602Z  2024-12-17T23:28:39.2722045Z  2024-12-17T23:28:39.2722744Z def get_rollout_state_from_issue(github_token: str, repo: str, issue_num: int) -> str: 2024-12-17T23:28:39.2723665Z  """ 2024-12-17T23:28:39.2724387Z  Gets the first comment of the issue, which contains the desired rollout state. 2024-12-17T23:28:39.2725202Z  2024-12-17T23:28:39.2726140Z  The default issue we use - https://github.com/pytorch/test-infra/issues/5132 2024-12-17T23:28:39.2726963Z  """ 2024-12-17T23:28:39.2727997Z  gh = get_gh_client(github_token) 2024-12-17T23:28:39.2728803Z  issue = get_issue(gh, repo, issue_num) 2024-12-17T23:28:39.2729613Z  return str(issue.get_comments()[0].body.strip("\n\t ")) 2024-12-17T23:28:39.2730276Z  2024-12-17T23:28:39.2730792Z  2024-12-17T23:28:39.2731488Z def download_json(url: str, headers: Dict[str, str], num_retries: int = 3) -> Any: 2024-12-17T23:28:39.2732329Z  for _ in range(num_retries): 2024-12-17T23:28:39.2732985Z  try: 2024-12-17T23:28:39.2733548Z  req = Request(url=url, headers=headers) 2024-12-17T23:28:39.2734342Z  content = urlopen(req, timeout=5).read().decode("utf-8") 2024-12-17T23:28:39.2735153Z  return json.loads(content) 2024-12-17T23:28:39.2735840Z  except Exception as e: 2024-12-17T23:28:39.2736507Z  log.warning(f"Could not download {url}: {e}") 2024-12-17T23:28:39.2737223Z  2024-12-17T23:28:39.2737903Z  log.warning(f"All {num_retries} retries exhausted, downloading {url} failed") 2024-12-17T23:28:39.2738702Z  return {} 2024-12-17T23:28:39.2739524Z  2024-12-17T23:28:39.2740240Z  2024-12-17T23:28:39.2740941Z @lru_cache(maxsize=None) 2024-12-17T23:28:39.2742123Z def get_pr_info(github_repo: str, github_token: str, pr_number: int) -> Dict[str, Any]: 2024-12-17T23:28:39.2742972Z  """ 2024-12-17T23:28:39.2743497Z  Dynamically get PR information 2024-12-17T23:28:39.2744173Z  """ 2024-12-17T23:28:39.2744768Z  github_api = f"https://api.github.com/repos/{github_repo}" 2024-12-17T23:28:39.2745500Z  headers = { 2024-12-17T23:28:39.2746209Z  "Accept": "application/vnd.github.v3+json", 2024-12-17T23:28:39.2746926Z  "Authorization": f"token {github_token}", 2024-12-17T23:28:39.2747570Z  } 2024-12-17T23:28:39.2748191Z  json_response: Dict[str, Any] = download_json( 2024-12-17T23:28:39.2749077Z  url=f"{github_api}/issues/{pr_number}", 2024-12-17T23:28:39.2749728Z  headers=headers, 2024-12-17T23:28:39.2750363Z  ) 2024-12-17T23:28:39.2750801Z  2024-12-17T23:28:39.2751244Z  if not json_response: 2024-12-17T23:28:39.2752065Z  log.warning(f"Failed to get the labels for #{pr_number}") 2024-12-17T23:28:39.2752765Z  return {} 2024-12-17T23:28:39.2753266Z  2024-12-17T23:28:39.2753822Z  return json_response 2024-12-17T23:28:39.2754339Z  2024-12-17T23:28:39.2754754Z  2024-12-17T23:28:39.2755531Z def get_labels(github_repo: str, github_token: str, pr_number: int) -> Set[str]: 2024-12-17T23:28:39.2756328Z  """ 2024-12-17T23:28:39.2756973Z  Dynamically get the latest list of labels from the pull request 2024-12-17T23:28:39.2757821Z  """ 2024-12-17T23:28:39.2758390Z  pr_info = get_pr_info(github_repo, github_token, pr_number) 2024-12-17T23:28:39.2759087Z  return { 2024-12-17T23:28:39.2759891Z  label.get("name") for label in pr_info.get("labels", []) if label.get("name") 2024-12-17T23:28:39.2760676Z  } 2024-12-17T23:28:39.2761074Z  2024-12-17T23:28:39.2761615Z  2024-12-17T23:28:39.2762060Z def main() -> None: 2024-12-17T23:28:39.2762552Z  args = parse_args() 2024-12-17T23:28:39.2763187Z  2024-12-17T23:28:39.2763699Z  runner_label_prefix = DEFAULT_LABEL_PREFIX 2024-12-17T23:28:39.2764278Z  2024-12-17T23:28:39.2764833Z  # Check if the PR is opt-out 2024-12-17T23:28:39.2765599Z  if args.pr_number: 2024-12-17T23:28:39.2766371Z  labels = get_labels(args.github_repo, args.github_token, int(args.pr_number)) 2024-12-17T23:28:39.2767558Z  if OPT_OUT_LABEL in labels: 2024-12-17T23:28:39.2768241Z  log.info( 2024-12-17T23:28:39.2769019Z  f"Opt-out runner determinator because #{args.pr_number} has {OPT_OUT_LABEL} label" 2024-12-17T23:28:39.2769985Z  ) 2024-12-17T23:28:39.2770690Z  set_github_output(GH_OUTPUT_KEY_LABEL_TYPE, runner_label_prefix) 2024-12-17T23:28:39.2771516Z  sys.exit() 2024-12-17T23:28:39.2772027Z  2024-12-17T23:28:39.2772473Z  try: 2024-12-17T23:28:39.2773075Z  rollout_state = get_rollout_state_from_issue( 2024-12-17T23:28:39.2773904Z  args.github_token, args.github_issue_repo, args.github_issue 2024-12-17T23:28:39.2774665Z  ) 2024-12-17T23:28:39.2775169Z  2024-12-17T23:28:39.2775639Z  username = get_potential_pr_author( 2024-12-17T23:28:39.2776293Z  args.github_token, 2024-12-17T23:28:39.2776947Z  args.github_repo, 2024-12-17T23:28:39.2777528Z  args.github_actor, 2024-12-17T23:28:39.2778149Z  args.github_ref_type, 2024-12-17T23:28:39.2778805Z  args.github_branch, 2024-12-17T23:28:39.2779381Z  ) 2024-12-17T23:28:39.2779847Z  2024-12-17T23:28:39.2780466Z  is_canary = args.github_repo == "pytorch/pytorch-canary" 2024-12-17T23:28:39.2781162Z  2024-12-17T23:28:39.2781677Z  runner_label_prefix = get_runner_prefix( 2024-12-17T23:28:39.2782368Z  rollout_state, 2024-12-17T23:28:39.2782981Z  (args.github_issue_owner, username), 2024-12-17T23:28:39.2783634Z  args.github_branch, 2024-12-17T23:28:39.2784320Z  args.eligible_experiments, 2024-12-17T23:28:39.2784934Z  is_canary, 2024-12-17T23:28:39.2785472Z  ) 2024-12-17T23:28:39.2785977Z  2024-12-17T23:28:39.2786433Z  except Exception as e: 2024-12-17T23:28:39.2787177Z  log.error( 2024-12-17T23:28:39.2788121Z  f"Failed to get issue. Defaulting to Meta runners and no experiments. Exception: {e}" 2024-12-17T23:28:39.2788988Z  ) 2024-12-17T23:28:39.2789413Z  2024-12-17T23:28:39.2790097Z  set_github_output(GH_OUTPUT_KEY_LABEL_TYPE, runner_label_prefix) 2024-12-17T23:28:39.2790857Z  2024-12-17T23:28:39.2791252Z  2024-12-17T23:28:39.2791766Z if __name__ == "__main__": 2024-12-17T23:28:39.2792329Z  main() 2024-12-17T23:28:39.2792781Z  2024-12-17T23:28:39.2793256Z EOF 2024-12-17T23:28:39.2793722Z  2024-12-17T23:28:39.2794160Z cat runner_determinator.py 2024-12-17T23:28:39.3147482Z shell: /usr/bin/bash -e {0} 2024-12-17T23:28:39.3148413Z env: 2024-12-17T23:28:39.3149716Z GITHUB_TOKEN: *** 2024-12-17T23:28:39.3150689Z ISSUE_NUMBER: 5132 2024-12-17T23:28:39.3151413Z TRIGGERING_ACTOR: malfet 2024-12-17T23:28:39.3152133Z ISSUE_OWNER: 2024-12-17T23:28:39.3152637Z CHECK_EXPERIMENTS: 2024-12-17T23:28:39.3153091Z PR_NUMBER: 2024-12-17T23:28:39.3153666Z ##[endgroup] 2024-12-17T23:28:39.3396086Z # flake8: noqa: G004 2024-12-17T23:28:39.3396486Z 2024-12-17T23:28:39.3397294Z # Note: Copies of this script in runner_determinator.py and _runner-determinator.yml 2024-12-17T23:28:39.3398453Z # must be kept in sync. You can do it easily by running the following command: 2024-12-17T23:28:39.3399295Z # python .github/scripts/update_runner_determinator.py 2024-12-17T23:28:39.3399801Z 2024-12-17T23:28:39.3399966Z """ 2024-12-17T23:28:39.3400958Z This runner determinator is used to determine which set of runners to run a 2024-12-17T23:28:39.3401909Z GitHub job on. It uses the first comment of a GitHub issue (by default 2024-12-17T23:28:39.3402807Z https://github.com/pytorch/test-infra/issues/5132) to define the configuration 2024-12-17T23:28:39.3403790Z of which runners should be used to run which job. 2024-12-17T23:28:39.3404226Z 2024-12-17T23:28:39.3404649Z The configuration has two parts, the settings and a list of opted-in users, 2024-12-17T23:28:39.3405540Z separated by a line containing "---". If the line is not present, the 2024-12-17T23:28:39.3406545Z settings are considered to be empty with only the second part, the user 2024-12-17T23:28:39.3407532Z list, defined. 2024-12-17T23:28:39.3407830Z 2024-12-17T23:28:39.3408196Z The first part is a YAML block that defines the rollout settings. This can be 2024-12-17T23:28:39.3409276Z used to define any settings that are needed to determine which runners to use. 2024-12-17T23:28:39.3410192Z It's fields are defined by the RolloutSettings class below. 2024-12-17T23:28:39.3410647Z 2024-12-17T23:28:39.3411110Z The second part is a list of users who are explicitly opted in to the LF fleet. 2024-12-17T23:28:39.3412033Z The user list is also a comma separated list of additional features or 2024-12-17T23:28:39.3412825Z experiments which the user could be opted in to. 2024-12-17T23:28:39.3413241Z 2024-12-17T23:28:39.3413536Z The user list has the following rules: 2024-12-17T23:28:39.3413931Z 2024-12-17T23:28:39.3414261Z - Users are GitHub usernames, which must start with the @ prefix 2024-12-17T23:28:39.3415159Z - Each user is also a comma-separated list of features/experiments to enable 2024-12-17T23:28:39.3416034Z - A "#" prefix opts the user out of all experiments 2024-12-17T23:28:39.3416472Z 2024-12-17T23:28:39.3416659Z Example config: 2024-12-17T23:28:39.3417175Z # A list of experiments that can be opted into. 2024-12-17T23:28:39.3417951Z # This defines the behavior they'll induce when opted into. 2024-12-17T23:28:39.3418690Z # Expected syntax is: 2024-12-17T23:28:39.3419351Z # [experiment_name]: # Name of the experiment. Also used for the label prefix. 2024-12-17T23:28:39.3420444Z # rollout_perc: [int] # % of workflows to run with this experiment when users are not opted in. 2024-12-17T23:28:39.3421085Z 2024-12-17T23:28:39.3421482Z experiments: 2024-12-17T23:28:39.3421927Z lf: 2024-12-17T23:28:39.3422443Z rollout_percent: 25 2024-12-17T23:28:39.3422980Z all_branches: false 2024-12-17T23:28:39.3423515Z default: true 2024-12-17T23:28:39.3424117Z --- 2024-12-17T23:28:39.3424379Z 2024-12-17T23:28:39.3424632Z # Opt-ins: 2024-12-17T23:28:39.3425280Z # Users can opt into the LF fleet by adding their GitHub username to this list 2024-12-17T23:28:39.3426244Z # and specifying experiments to enable in a comma-separated list. 2024-12-17T23:28:39.3427099Z # To always opt out of an experiment, prefix it with a "-". 2024-12-17T23:28:39.3427793Z # Experiments should be from the above list. 2024-12-17T23:28:39.3428202Z 2024-12-17T23:28:39.3428462Z @User1,-lf,split_build 2024-12-17T23:28:39.3428977Z @User2,lf 2024-12-17T23:28:39.3429403Z @User3,split_build 2024-12-17T23:28:39.3429925Z """ 2024-12-17T23:28:39.3430148Z 2024-12-17T23:28:39.3430365Z import json 2024-12-17T23:28:39.3430784Z import logging 2024-12-17T23:28:39.3431276Z import os 2024-12-17T23:28:39.3431742Z import random 2024-12-17T23:28:39.3432143Z import re 2024-12-17T23:28:39.3432606Z import sys 2024-12-17T23:28:39.3433115Z from argparse import ArgumentParser 2024-12-17T23:28:39.3433662Z from functools import lru_cache 2024-12-17T23:28:39.3434258Z from logging import LogRecord 2024-12-17T23:28:39.3435034Z from typing import Any, Dict, FrozenSet, Iterable, List, NamedTuple, Set, Tuple 2024-12-17T23:28:39.3435871Z from urllib.request import Request, urlopen 2024-12-17T23:28:39.3436273Z 2024-12-17T23:28:39.3436518Z import yaml 2024-12-17T23:28:39.3437000Z from github import Auth, Github 2024-12-17T23:28:39.3437671Z from github.Issue import Issue 2024-12-17T23:28:39.3438011Z 2024-12-17T23:28:39.3438017Z 2024-12-17T23:28:39.3438316Z DEFAULT_LABEL_PREFIX = "" # use meta runners 2024-12-17T23:28:39.3439091Z WORKFLOW_LABEL_LF = "lf." # use runners from the linux foundation 2024-12-17T23:28:39.3439976Z WORKFLOW_LABEL_LF_CANARY = "lf.c." # use canary runners from the linux foundation 2024-12-17T23:28:39.3440557Z 2024-12-17T23:28:39.3440912Z GITHUB_OUTPUT = os.getenv("GITHUB_OUTPUT", "") 2024-12-17T23:28:39.3441567Z GH_OUTPUT_KEY_AMI = "runner-ami" 2024-12-17T23:28:39.3442133Z GH_OUTPUT_KEY_LABEL_TYPE = "label-type" 2024-12-17T23:28:39.3442777Z OPT_OUT_LABEL = "no-runner-experiments" 2024-12-17T23:28:39.3443190Z 2024-12-17T23:28:39.3443398Z SETTING_EXPERIMENTS = "experiments" 2024-12-17T23:28:39.3443765Z 2024-12-17T23:28:39.3444032Z LF_FLEET_EXPERIMENT = "lf" 2024-12-17T23:28:39.3444594Z CANARY_FLEET_SUFFIX = ".c" 2024-12-17T23:28:39.3444947Z 2024-12-17T23:28:39.3444958Z 2024-12-17T23:28:39.3445162Z class Experiment(NamedTuple): 2024-12-17T23:28:39.3445717Z rollout_perc: float = ( 2024-12-17T23:28:39.3446423Z 0 # Percentage of workflows to experiment on when user is not opted-in. 2024-12-17T23:28:39.3447170Z ) 2024-12-17T23:28:39.3447922Z all_branches: bool = ( 2024-12-17T23:28:39.3448693Z False # If True, the experiment is also enabled on the exception branches 2024-12-17T23:28:39.3449449Z ) 2024-12-17T23:28:39.3449893Z default: bool = ( 2024-12-17T23:28:39.3450532Z True # If True, the experiment is enabled by default for all queries 2024-12-17T23:28:39.3451245Z ) 2024-12-17T23:28:39.3451456Z 2024-12-17T23:28:39.3451702Z # Add more fields as needed 2024-12-17T23:28:39.3452003Z 2024-12-17T23:28:39.3452010Z 2024-12-17T23:28:39.3452320Z class Settings(NamedTuple): 2024-12-17T23:28:39.3452794Z """ 2024-12-17T23:28:39.3453327Z Settings for the experiments that can be opted into. 2024-12-17T23:28:39.3454028Z """ 2024-12-17T23:28:39.3454242Z 2024-12-17T23:28:39.3454461Z experiments: Dict[str, Experiment] = {} 2024-12-17T23:28:39.3454892Z 2024-12-17T23:28:39.3454897Z 2024-12-17T23:28:39.3455117Z class ColorFormatter(logging.Formatter): 2024-12-17T23:28:39.3455863Z """Color codes the log messages based on the log level""" 2024-12-17T23:28:39.3456493Z 2024-12-17T23:28:39.3456687Z COLORS = { 2024-12-17T23:28:39.3457155Z "WARNING": "\033[33m", # Yellow 2024-12-17T23:28:39.3457801Z "ERROR": "\033[31m", # Red 2024-12-17T23:28:39.3458338Z "CRITICAL": "\033[31m", # Red 2024-12-17T23:28:39.3458884Z "INFO": "\033[0m", # Reset 2024-12-17T23:28:39.3459512Z "DEBUG": "\033[0m", # Reset 2024-12-17T23:28:39.3460009Z } 2024-12-17T23:28:39.3460254Z 2024-12-17T23:28:39.3460489Z def format(self, record: LogRecord) -> str: 2024-12-17T23:28:39.3461386Z log_color = self.COLORS.get(record.levelname, "\033[0m") # Default to reset 2024-12-17T23:28:39.3462190Z record.msg = f"{log_color}{record.msg}\033[0m" 2024-12-17T23:28:39.3462850Z return super().format(record) 2024-12-17T23:28:39.3463286Z 2024-12-17T23:28:39.3463294Z 2024-12-17T23:28:39.3463539Z handler = logging.StreamHandler() 2024-12-17T23:28:39.3464306Z handler.setFormatter(ColorFormatter(fmt="%(levelname)-8s: %(message)s")) 2024-12-17T23:28:39.3464868Z 2024-12-17T23:28:39.3465130Z log = logging.getLogger(os.path.basename(__file__)) 2024-12-17T23:28:39.3465902Z log.addHandler(handler) 2024-12-17T23:28:39.3466416Z log.setLevel(logging.INFO) 2024-12-17T23:28:39.3466714Z 2024-12-17T23:28:39.3466720Z 2024-12-17T23:28:39.3466985Z def set_github_output(key: str, value: str) -> None: 2024-12-17T23:28:39.3467687Z """ 2024-12-17T23:28:39.3468259Z Defines outputs of the github action that invokes this script 2024-12-17T23:28:39.3468912Z """ 2024-12-17T23:28:39.3469421Z if not GITHUB_OUTPUT: 2024-12-17T23:28:39.3470533Z # See https://github.blog/changelog/2022-10-11-github-actions-deprecating-save-state-and-set-output-commands/ for deprecation notice 2024-12-17T23:28:39.3471848Z log.warning( 2024-12-17T23:28:39.3472835Z "No env var found for GITHUB_OUTPUT, you must be running this code locally. Falling back to the deprecated print method." 2024-12-17T23:28:39.3473854Z ) 2024-12-17T23:28:39.3483906Z print(f"::set-output name={key}::{value}") 2024-12-17T23:28:39.3484687Z return 2024-12-17T23:28:39.3484970Z 2024-12-17T23:28:39.3485207Z with open(GITHUB_OUTPUT, "a") as f: 2024-12-17T23:28:39.3485831Z log.info(f"Setting output: {key}='{value}'") 2024-12-17T23:28:39.3486515Z f.write(f"{key}={value}\n") 2024-12-17T23:28:39.3486911Z 2024-12-17T23:28:39.3486917Z 2024-12-17T23:28:39.3487234Z def _str_comma_separated_to_set(value: str) -> FrozenSet[str]: 2024-12-17T23:28:39.3488191Z return frozenset( 2024-12-17T23:28:39.3488935Z filter(lambda itm: itm != "", map(str.strip, value.strip(" \n\t").split(","))) 2024-12-17T23:28:39.3489722Z ) 2024-12-17T23:28:39.3489931Z 2024-12-17T23:28:39.3489938Z 2024-12-17T23:28:39.3490155Z def parse_args() -> Any: 2024-12-17T23:28:39.3490814Z parser = ArgumentParser("Get dynamic rollout settings") 2024-12-17T23:28:39.3491747Z parser.add_argument("--github-token", type=str, required=True, help="GitHub token") 2024-12-17T23:28:39.3492548Z parser.add_argument( 2024-12-17T23:28:39.3493111Z "--github-issue-repo", 2024-12-17T23:28:39.3493644Z type=str, 2024-12-17T23:28:39.3494090Z required=False, 2024-12-17T23:28:39.3494659Z default="pytorch/test-infra", 2024-12-17T23:28:39.3495263Z help="GitHub repo to get the issue", 2024-12-17T23:28:39.3495819Z ) 2024-12-17T23:28:39.3496321Z parser.add_argument( 2024-12-17T23:28:39.3496836Z "--github-repo", 2024-12-17T23:28:39.3497304Z type=str, 2024-12-17T23:28:39.3497815Z required=True, 2024-12-17T23:28:39.3498343Z help="GitHub repo where CI is running", 2024-12-17T23:28:39.3498921Z ) 2024-12-17T23:28:39.3499416Z parser.add_argument( 2024-12-17T23:28:39.3500075Z "--github-issue", type=int, required=True, help="GitHub issue number" 2024-12-17T23:28:39.3500780Z ) 2024-12-17T23:28:39.3501262Z parser.add_argument( 2024-12-17T23:28:39.3502131Z "--github-actor", type=str, required=True, help="GitHub triggering_actor" 2024-12-17T23:28:39.3502904Z ) 2024-12-17T23:28:39.3503412Z parser.add_argument( 2024-12-17T23:28:39.3504114Z "--github-issue-owner", type=str, required=True, help="GitHub issue owner" 2024-12-17T23:28:39.3504867Z ) 2024-12-17T23:28:39.3505331Z parser.add_argument( 2024-12-17T23:28:39.3506036Z "--github-branch", type=str, required=True, help="Current GitHub branch or tag" 2024-12-17T23:28:39.3506813Z ) 2024-12-17T23:28:39.3507280Z parser.add_argument( 2024-12-17T23:28:39.3507801Z "--github-ref-type", 2024-12-17T23:28:39.3508300Z type=str, 2024-12-17T23:28:39.3508812Z required=True, 2024-12-17T23:28:39.3509363Z help="Current GitHub ref type, branch or tag", 2024-12-17T23:28:39.3509955Z ) 2024-12-17T23:28:39.3510443Z parser.add_argument( 2024-12-17T23:28:39.3510966Z "--eligible-experiments", 2024-12-17T23:28:39.3511521Z type=_str_comma_separated_to_set, 2024-12-17T23:28:39.3512142Z required=False, 2024-12-17T23:28:39.3512639Z default="", 2024-12-17T23:28:39.3513520Z help="comma separated list of experiments to check, if omitted all experiments marked with default=True are checked", 2024-12-17T23:28:39.3514532Z ) 2024-12-17T23:28:39.3514977Z parser.add_argument( 2024-12-17T23:28:39.3515468Z "--pr-number", 2024-12-17T23:28:39.3515992Z type=str, 2024-12-17T23:28:39.3516466Z required=False, 2024-12-17T23:28:39.3516924Z default="", 2024-12-17T23:28:39.3517525Z help="the optional PR number where this is run", 2024-12-17T23:28:39.3518138Z ) 2024-12-17T23:28:39.3518518Z 2024-12-17T23:28:39.3518741Z return parser.parse_args() 2024-12-17T23:28:39.3519151Z 2024-12-17T23:28:39.3519157Z 2024-12-17T23:28:39.3519462Z def get_gh_client(github_token: str) -> Github: 2024-12-17T23:28:39.3520062Z auth = Auth.Token(github_token) 2024-12-17T23:28:39.3520612Z return Github(auth=auth) 2024-12-17T23:28:39.3521005Z 2024-12-17T23:28:39.3521011Z 2024-12-17T23:28:39.3521375Z def get_issue(gh: Github, repo: str, issue_num: int) -> Issue: 2024-12-17T23:28:39.3522031Z repo = gh.get_repo(repo) 2024-12-17T23:28:39.3522582Z return repo.get_issue(number=issue_num) 2024-12-17T23:28:39.3523019Z 2024-12-17T23:28:39.3523026Z 2024-12-17T23:28:39.3523283Z def get_potential_pr_author( 2024-12-17T23:28:39.3523945Z github_token: str, repo: str, username: str, ref_type: str, ref_name: str 2024-12-17T23:28:39.3524751Z ) -> str: 2024-12-17T23:28:39.3525435Z # If the trigger was a new tag added by a bot, this is a ciflow case 2024-12-17T23:28:39.3526265Z # Fetch the actual username from the original PR. The PR number is 2024-12-17T23:28:39.3527064Z # embedded in the tag name: ciflow// 2024-12-17T23:28:39.3528203Z 2024-12-17T23:28:39.3528435Z gh = get_gh_client(github_token) 2024-12-17T23:28:39.3528825Z 2024-12-17T23:28:39.3529161Z if username == "pytorch-bot[bot]" and ref_type == "tag": 2024-12-17T23:28:39.3529794Z split_tag = ref_name.split("/") 2024-12-17T23:28:39.3530446Z if ( 2024-12-17T23:28:39.3530906Z len(split_tag) == 3 2024-12-17T23:28:39.3531396Z and split_tag[0] == "ciflow" 2024-12-17T23:28:39.3532062Z and split_tag[2].isnumeric() 2024-12-17T23:28:39.3532640Z ): 2024-12-17T23:28:39.3533033Z pr_number = split_tag[2] 2024-12-17T23:28:39.3533654Z try: 2024-12-17T23:28:39.3534156Z repository = gh.get_repo(repo) 2024-12-17T23:28:39.3535088Z pull = repository.get_pull(number=int(pr_number)) 2024-12-17T23:28:39.3535895Z except Exception as e: 2024-12-17T23:28:39.3536485Z raise Exception( # noqa: TRY002 2024-12-17T23:28:39.3537188Z f"issue with pull request {pr_number} from repo {repository}" 2024-12-17T23:28:39.3537983Z ) from e 2024-12-17T23:28:39.3538511Z return pull.user.login 2024-12-17T23:28:39.3539278Z # In all other cases, return the original input username 2024-12-17T23:28:39.3540046Z return username 2024-12-17T23:28:39.3540307Z 2024-12-17T23:28:39.3540314Z 2024-12-17T23:28:39.3540621Z def is_exception_branch(branch: str) -> bool: 2024-12-17T23:28:39.3541172Z """ 2024-12-17T23:28:39.3541961Z Branches that get opted out of experiments by default, until they're explicitly enabled. 2024-12-17T23:28:39.3542802Z """ 2024-12-17T23:28:39.3543351Z return branch.split("/")[0] in {"main", "nightly", "release", "landchecks"} 2024-12-17T23:28:39.3544013Z 2024-12-17T23:28:39.3544018Z 2024-12-17T23:28:39.3544226Z def load_yaml(yaml_text: str) -> Any: 2024-12-17T23:28:39.3544808Z try: 2024-12-17T23:28:39.3545303Z data = yaml.safe_load(yaml_text) 2024-12-17T23:28:39.3545881Z return data 2024-12-17T23:28:39.3546358Z except yaml.YAMLError: 2024-12-17T23:28:39.3546853Z log.exception("Error loading YAML") 2024-12-17T23:28:39.3547529Z raise 2024-12-17T23:28:39.3547814Z 2024-12-17T23:28:39.3547821Z 2024-12-17T23:28:39.3548245Z def extract_settings_user_opt_in_from_text(rollout_state: str) -> Tuple[str, str]: 2024-12-17T23:28:39.3549158Z """ 2024-12-17T23:28:39.3549864Z Extracts the text with settings, if any, and the opted in users from the rollout state. 2024-12-17T23:28:39.3550497Z 2024-12-17T23:28:39.3550851Z If the issue body contains "---" then the text above that is the settings 2024-12-17T23:28:39.3551701Z and the text below is the list of opted in users. 2024-12-17T23:28:39.3552150Z 2024-12-17T23:28:39.3552536Z If it doesn't contain "---" then the settings are empty and the rest is the users. 2024-12-17T23:28:39.3553468Z """ 2024-12-17T23:28:39.3554034Z rollout_state_parts = rollout_state.split("---") 2024-12-17T23:28:39.3554674Z if len(rollout_state_parts) >= 2: 2024-12-17T23:28:39.3555333Z return rollout_state_parts[0], rollout_state_parts[1] 2024-12-17T23:28:39.3556051Z else: 2024-12-17T23:28:39.3556502Z return "", rollout_state 2024-12-17T23:28:39.3556860Z 2024-12-17T23:28:39.3556866Z 2024-12-17T23:28:39.3557078Z class UserOptins(Dict[str, List[str]]): 2024-12-17T23:28:39.3557712Z """ 2024-12-17T23:28:39.3558302Z Dictionary of users with a list of features they have opted into 2024-12-17T23:28:39.3558966Z """ 2024-12-17T23:28:39.3559217Z 2024-12-17T23:28:39.3559223Z 2024-12-17T23:28:39.3559642Z def parse_user_opt_in_from_text(user_optin_text: str) -> UserOptins: 2024-12-17T23:28:39.3560362Z """ 2024-12-17T23:28:39.3561103Z Parse the user opt-in text into a key value pair of username and the list of features they have opted into 2024-12-17T23:28:39.3561823Z 2024-12-17T23:28:39.3562510Z Users are GitHub usernames with the @ prefix. Each user is also a comma-separated list of features/experiments to enable. 2024-12-17T23:28:39.3563571Z - Example line: "@User1,lf,split_build" 2024-12-17T23:28:39.3564299Z - A "#" prefix indicates the user is opted out of all experiments 2024-12-17T23:28:39.3564812Z 2024-12-17T23:28:39.3564819Z 2024-12-17T23:28:39.3565058Z """ 2024-12-17T23:28:39.3565524Z optins = UserOptins() 2024-12-17T23:28:39.3566132Z for user in user_optin_text.split("\n"): 2024-12-17T23:28:39.3566762Z user = user.strip("\r\n\t -") 2024-12-17T23:28:39.3567592Z if not user or not user.startswith("@"): 2024-12-17T23:28:39.3568243Z # Not a valid user. Skip 2024-12-17T23:28:39.3568817Z continue 2024-12-17T23:28:39.3569128Z 2024-12-17T23:28:39.3569320Z if user: 2024-12-17T23:28:39.3569813Z usr_name = user.split(",")[0].strip("@") 2024-12-17T23:28:39.3570577Z optins[usr_name] = [exp.strip(" ") for exp in user.split(",")[1:]] 2024-12-17T23:28:39.3571133Z 2024-12-17T23:28:39.3571336Z return optins 2024-12-17T23:28:39.3571585Z 2024-12-17T23:28:39.3571591Z 2024-12-17T23:28:39.3571930Z def is_valid_experiment_name(experiment_name: str) -> bool: 2024-12-17T23:28:39.3572779Z """ 2024-12-17T23:28:39.3573299Z Check if the experiment name is valid. 2024-12-17T23:28:39.3573886Z A valid name: 2024-12-17T23:28:39.3574603Z - Contains only alphanumeric characters and the special characters "_" & "-" 2024-12-17T23:28:39.3575624Z - The special characters "_" & "-" shouldn't be the first or last characters 2024-12-17T23:28:39.3576396Z - Cannot contain spaces 2024-12-17T23:28:39.3576923Z """ 2024-12-17T23:28:39.3577203Z 2024-12-17T23:28:39.3577476Z valid_char_regex = r"^[a-zA-Z0-9]([\w-]*[a-zA-Z0-9])?$" 2024-12-17T23:28:39.3578241Z valid = bool(re.match(valid_char_regex, experiment_name)) 2024-12-17T23:28:39.3578694Z 2024-12-17T23:28:39.3578997Z if valid: 2024-12-17T23:28:39.3579405Z return True 2024-12-17T23:28:39.3579689Z 2024-12-17T23:28:39.3579869Z log.error( 2024-12-17T23:28:39.3581459Z f"Invalid experiment name: {experiment_name}. Experiment names should only contain alphanumeric characters, '_', and '-'. They cannot contain spaces, and the special characters '_' and '-' cannot be the first or last characters." 2024-12-17T23:28:39.3583041Z ) 2024-12-17T23:28:39.3583423Z return False 2024-12-17T23:28:39.3583780Z 2024-12-17T23:28:39.3583786Z 2024-12-17T23:28:39.3584116Z def parse_settings_from_text(settings_text: str) -> Settings: 2024-12-17T23:28:39.3584794Z """ 2024-12-17T23:28:39.3585415Z Parse the experiments from the issue body into a list of ExperimentSettings 2024-12-17T23:28:39.3586252Z """ 2024-12-17T23:28:39.3586668Z try: 2024-12-17T23:28:39.3587086Z if settings_text: 2024-12-17T23:28:39.3587974Z # Escape the backtick as well so that we can have the settings in a code block on the GH issue 2024-12-17T23:28:39.3589010Z # for easy reading 2024-12-17T23:28:39.3589836Z # Note: Using ascii for the backtick so that the cat step in _runner-determinator.yml doesn't choke on 2024-12-17T23:28:39.3590872Z # the backtick character in shell commands. 2024-12-17T23:28:39.3591553Z backtick = chr(96) # backtick character 2024-12-17T23:28:39.3592240Z settings_text = settings_text.strip(f"\r\n\t{backtick} ") 2024-12-17T23:28:39.3593017Z settings = load_yaml(settings_text) 2024-12-17T23:28:39.3593402Z 2024-12-17T23:28:39.3593867Z # For now we just load experiments. We can expand this if/when we add more settings 2024-12-17T23:28:39.3594655Z experiments = {} 2024-12-17T23:28:39.3595036Z 2024-12-17T23:28:39.3595416Z for exp_name, exp_settings in settings.get(SETTING_EXPERIMENTS).items(): 2024-12-17T23:28:39.3596246Z if not is_valid_experiment_name(exp_name): 2024-12-17T23:28:39.3597372Z # Exclude invalid experiments from the list. We log an error, but don't raise an exception so that other experiments can still be processed. 2024-12-17T23:28:39.3598502Z continue 2024-12-17T23:28:39.3598855Z 2024-12-17T23:28:39.3599057Z valid_settings = {} 2024-12-17T23:28:39.3599687Z for setting in exp_settings: 2024-12-17T23:28:39.3600410Z if setting not in Experiment._fields: 2024-12-17T23:28:39.3601046Z log.warning( 2024-12-17T23:28:39.3601791Z f"Unexpected setting in experiment: {setting} = {exp_settings[setting]}" 2024-12-17T23:28:39.3602625Z ) 2024-12-17T23:28:39.3603175Z else: 2024-12-17T23:28:39.3603788Z valid_settings[setting] = exp_settings[setting] 2024-12-17T23:28:39.3604286Z 2024-12-17T23:28:39.3604645Z experiments[exp_name] = Experiment(**valid_settings) 2024-12-17T23:28:39.3605296Z return Settings(experiments) 2024-12-17T23:28:39.3605683Z 2024-12-17T23:28:39.3605858Z except Exception: 2024-12-17T23:28:39.3606491Z log.exception("Failed to parse settings") 2024-12-17T23:28:39.3606888Z 2024-12-17T23:28:39.3607239Z return Settings() 2024-12-17T23:28:39.3608098Z 2024-12-17T23:28:39.3608105Z 2024-12-17T23:28:39.3608401Z def parse_settings(rollout_state: str) -> Settings: 2024-12-17T23:28:39.3609148Z """ 2024-12-17T23:28:39.3609601Z Parse settings, if any, from the rollout state. 2024-12-17T23:28:39.3610067Z 2024-12-17T23:28:39.3610418Z If the issue body contains "---" then the text above that is the settings 2024-12-17T23:28:39.3611317Z and the text below is the list of opted in users. 2024-12-17T23:28:39.3611730Z 2024-12-17T23:28:39.3612185Z If it doesn't contain "---" then the settings are empty and the default values are used. 2024-12-17T23:28:39.3612949Z """ 2024-12-17T23:28:39.3613660Z settings_text, _ = extract_settings_user_opt_in_from_text(rollout_state) 2024-12-17T23:28:39.3614484Z return parse_settings_from_text(settings_text) 2024-12-17T23:28:39.3614898Z 2024-12-17T23:28:39.3614905Z 2024-12-17T23:28:39.3615153Z def parse_users(rollout_state: str) -> UserOptins: 2024-12-17T23:28:39.3615848Z """ 2024-12-17T23:28:39.3616331Z Parse users from the rollout state. 2024-12-17T23:28:39.3616691Z 2024-12-17T23:28:39.3616851Z """ 2024-12-17T23:28:39.3617515Z _, users_text = extract_settings_user_opt_in_from_text(rollout_state) 2024-12-17T23:28:39.3618312Z return parse_user_opt_in_from_text(users_text) 2024-12-17T23:28:39.3618712Z 2024-12-17T23:28:39.3618717Z 2024-12-17T23:28:39.3619220Z def is_user_opted_in(user: str, user_optins: UserOptins, experiment_name: str) -> bool: 2024-12-17T23:28:39.3620006Z """ 2024-12-17T23:28:39.3620494Z Check if a user is opted into an experiment 2024-12-17T23:28:39.3621570Z """ 2024-12-17T23:28:39.3622082Z return experiment_name in user_optins.get(user, []) 2024-12-17T23:28:39.3622543Z 2024-12-17T23:28:39.3622549Z 2024-12-17T23:28:39.3622984Z def is_user_opted_out(user: str, user_optins: UserOptins, experiment_name: str) -> bool: 2024-12-17T23:28:39.3623829Z """ 2024-12-17T23:28:39.3624358Z Check if a user explicitly opted out of an experiment 2024-12-17T23:28:39.3625001Z """ 2024-12-17T23:28:39.3625622Z # if the experiment is prefixed with a "-", then it's an opt-out 2024-12-17T23:28:39.3626357Z experiment_optout = "-" + experiment_name 2024-12-17T23:28:39.3627046Z if experiment_optout not in user_optins.get(user, []): 2024-12-17T23:28:39.3627738Z return False 2024-12-17T23:28:39.3628036Z 2024-12-17T23:28:39.3628314Z if is_user_opted_in(user, user_optins, experiment_name): 2024-12-17T23:28:39.3628965Z log.warning( 2024-12-17T23:28:39.3629859Z f"User {user} is opted into experiment {experiment_name}, but also opted out of it. Defaulting to opting out" 2024-12-17T23:28:39.3630783Z ) 2024-12-17T23:28:39.3631038Z 2024-12-17T23:28:39.3631220Z return True 2024-12-17T23:28:39.3631466Z 2024-12-17T23:28:39.3631494Z 2024-12-17T23:28:39.3631760Z def get_runner_prefix( 2024-12-17T23:28:39.3632289Z rollout_state: str, 2024-12-17T23:28:39.3632769Z workflow_requestors: Iterable[str], 2024-12-17T23:28:39.3633408Z branch: str, 2024-12-17T23:28:39.3633969Z eligible_experiments: FrozenSet[str] = frozenset(), 2024-12-17T23:28:39.3634577Z is_canary: bool = False, 2024-12-17T23:28:39.3635150Z ) -> str: 2024-12-17T23:28:39.3635642Z settings = parse_settings(rollout_state) 2024-12-17T23:28:39.3636235Z user_optins = parse_users(rollout_state) 2024-12-17T23:28:39.3636651Z 2024-12-17T23:28:39.3636898Z fleet_prefix = "" 2024-12-17T23:28:39.3637395Z prefixes = [] 2024-12-17T23:28:39.3638037Z for experiment_name, experiment_settings in settings.experiments.items(): 2024-12-17T23:28:39.3639081Z if not experiment_settings.all_branches and is_exception_branch(branch): 2024-12-17T23:28:39.3639886Z log.info( 2024-12-17T23:28:39.3640593Z f"Branch {branch} is an exception branch. Not enabling experiment {experiment_name}." 2024-12-17T23:28:39.3641543Z ) 2024-12-17T23:28:39.3642146Z continue 2024-12-17T23:28:39.3642420Z 2024-12-17T23:28:39.3642608Z if eligible_experiments: 2024-12-17T23:28:39.3643314Z if experiment_name not in eligible_experiments: 2024-12-17T23:28:39.3644009Z exp_list = ", ".join(eligible_experiments) 2024-12-17T23:28:39.3644568Z log.info( 2024-12-17T23:28:39.3645463Z f"Skipping experiment '{experiment_name}', as it is not in the eligible_experiments list: {exp_list}" 2024-12-17T23:28:39.3646369Z ) 2024-12-17T23:28:39.3646769Z continue 2024-12-17T23:28:39.3647676Z elif not experiment_settings.default: 2024-12-17T23:28:39.3648310Z log.info( 2024-12-17T23:28:39.3648958Z f"Skipping experiment '{experiment_name}', as it is not a default experiment" 2024-12-17T23:28:39.3649859Z ) 2024-12-17T23:28:39.3650295Z continue 2024-12-17T23:28:39.3650555Z 2024-12-17T23:28:39.3650928Z # Is any workflow_requestor opted out to this experiment? 2024-12-17T23:28:39.3651599Z opted_out_users = [ 2024-12-17T23:28:39.3652104Z requestor 2024-12-17T23:28:39.3652663Z for requestor in workflow_requestors 2024-12-17T23:28:39.3653383Z if is_user_opted_out(requestor, user_optins, experiment_name) 2024-12-17T23:28:39.3654058Z ] 2024-12-17T23:28:39.3654277Z 2024-12-17T23:28:39.3654563Z if opted_out_users: 2024-12-17T23:28:39.3655065Z log.info( 2024-12-17T23:28:39.3655730Z f"{', '.join(opted_out_users)} have opted out of experiment {experiment_name}." 2024-12-17T23:28:39.3656543Z ) 2024-12-17T23:28:39.3657148Z continue 2024-12-17T23:28:39.3657443Z 2024-12-17T23:28:39.3657724Z # Is any workflow_requestor opted in to this experiment? 2024-12-17T23:28:39.3658470Z opted_in_users = [ 2024-12-17T23:28:39.3658955Z requestor 2024-12-17T23:28:39.3659469Z for requestor in workflow_requestors 2024-12-17T23:28:39.3660255Z if is_user_opted_in(requestor, user_optins, experiment_name) 2024-12-17T23:28:39.3660911Z ] 2024-12-17T23:28:39.3661161Z 2024-12-17T23:28:39.3661372Z enabled = False 2024-12-17T23:28:39.3661921Z if opted_in_users: 2024-12-17T23:28:39.3662405Z log.info( 2024-12-17T23:28:39.3663072Z f"{', '.join(opted_in_users)} have opted into experiment {experiment_name}." 2024-12-17T23:28:39.3663845Z ) 2024-12-17T23:28:39.3664274Z enabled = True 2024-12-17T23:28:39.3664619Z 2024-12-17T23:28:39.3664847Z elif experiment_settings.rollout_perc: 2024-12-17T23:28:39.3665811Z # If no user is opted in, then we randomly enable the experiment based on the rollout percentage 2024-12-17T23:28:39.3666805Z if random.uniform(0, 100) <= experiment_settings.rollout_perc: 2024-12-17T23:28:39.3667482Z log.info( 2024-12-17T23:28:39.3668602Z f"Based on rollout percentage of {experiment_settings.rollout_perc}%, enabling experiment {experiment_name}." 2024-12-17T23:28:39.3669613Z ) 2024-12-17T23:28:39.3670050Z enabled = True 2024-12-17T23:28:39.3670379Z 2024-12-17T23:28:39.3670623Z if enabled: 2024-12-17T23:28:39.3671132Z label = experiment_name 2024-12-17T23:28:39.3671706Z if experiment_name == LF_FLEET_EXPERIMENT: 2024-12-17T23:28:39.3672638Z # We give some special treatment to the "lf" experiment since determines the fleet we use 2024-12-17T23:28:39.3673594Z # - If it's enabled, then we always list it's prefix first 2024-12-17T23:28:39.3674367Z # - If we're in the canary branch, then we append ".c" to the lf prefix 2024-12-17T23:28:39.3675134Z if is_canary: 2024-12-17T23:28:39.3675721Z label += CANARY_FLEET_SUFFIX 2024-12-17T23:28:39.3676287Z fleet_prefix = label 2024-12-17T23:28:39.3677040Z else: 2024-12-17T23:28:39.3677574Z prefixes.append(label) 2024-12-17T23:28:39.3677930Z 2024-12-17T23:28:39.3678125Z if len(prefixes) > 1: 2024-12-17T23:28:39.3678693Z log.error( 2024-12-17T23:28:39.3679791Z f"Only a fleet and one other experiment can be enabled for a job at any time. Enabling {prefixes[0]} and ignoring the rest, which are {', '.join(prefixes[1:])}" 2024-12-17T23:28:39.3680950Z ) 2024-12-17T23:28:39.3681427Z prefixes = prefixes[:1] 2024-12-17T23:28:39.3681794Z 2024-12-17T23:28:39.3681993Z # Fleet always comes first 2024-12-17T23:28:39.3682530Z if fleet_prefix: 2024-12-17T23:28:39.3683056Z prefixes.insert(0, fleet_prefix) 2024-12-17T23:28:39.3683474Z 2024-12-17T23:28:39.3683729Z return ".".join(prefixes) + "." if prefixes else "" 2024-12-17T23:28:39.3684148Z 2024-12-17T23:28:39.3684153Z 2024-12-17T23:28:39.3684656Z def get_rollout_state_from_issue(github_token: str, repo: str, issue_num: int) -> str: 2024-12-17T23:28:39.3685488Z """ 2024-12-17T23:28:39.3686160Z Gets the first comment of the issue, which contains the desired rollout state. 2024-12-17T23:28:39.3686717Z 2024-12-17T23:28:39.3687157Z The default issue we use - https://github.com/pytorch/test-infra/issues/5132 2024-12-17T23:28:39.3688574Z """ 2024-12-17T23:28:39.3688999Z gh = get_gh_client(github_token) 2024-12-17T23:28:39.3689608Z issue = get_issue(gh, repo, issue_num) 2024-12-17T23:28:39.3690353Z return str(issue.get_comments()[0].body.strip("\n\t ")) 2024-12-17T23:28:39.3690810Z 2024-12-17T23:28:39.3690816Z 2024-12-17T23:28:39.3691226Z def download_json(url: str, headers: Dict[str, str], num_retries: int = 3) -> Any: 2024-12-17T23:28:39.3692238Z for _ in range(num_retries): 2024-12-17T23:28:39.3692836Z try: 2024-12-17T23:28:39.3693298Z req = Request(url=url, headers=headers) 2024-12-17T23:28:39.3694007Z content = urlopen(req, timeout=5).read().decode("utf-8") 2024-12-17T23:28:39.3694776Z return json.loads(content) 2024-12-17T23:28:39.3695344Z except Exception as e: 2024-12-17T23:28:39.3695942Z log.warning(f"Could not download {url}: {e}") 2024-12-17T23:28:39.3696361Z 2024-12-17T23:28:39.3696865Z log.warning(f"All {num_retries} retries exhausted, downloading {url} failed") 2024-12-17T23:28:39.3697608Z return {} 2024-12-17T23:28:39.3697879Z 2024-12-17T23:28:39.3697885Z 2024-12-17T23:28:39.3698080Z @lru_cache(maxsize=None) 2024-12-17T23:28:39.3698893Z def get_pr_info(github_repo: str, github_token: str, pr_number: int) -> Dict[str, Any]: 2024-12-17T23:28:39.3699689Z """ 2024-12-17T23:28:39.3700106Z Dynamically get PR information 2024-12-17T23:28:39.3700728Z """ 2024-12-17T23:28:39.3701265Z github_api = f"https://api.github.com/repos/{github_repo}" 2024-12-17T23:28:39.3701898Z headers = { 2024-12-17T23:28:39.3702495Z "Accept": "application/vnd.github.v3+json", 2024-12-17T23:28:39.3703150Z "Authorization": f"token {github_token}", 2024-12-17T23:28:39.3703707Z } 2024-12-17T23:28:39.3704265Z json_response: Dict[str, Any] = download_json( 2024-12-17T23:28:39.3704918Z url=f"{github_api}/issues/{pr_number}", 2024-12-17T23:28:39.3705481Z headers=headers, 2024-12-17T23:28:39.3706042Z ) 2024-12-17T23:28:39.3706250Z 2024-12-17T23:28:39.3706474Z if not json_response: 2024-12-17T23:28:39.3707053Z log.warning(f"Failed to get the labels for #{pr_number}") 2024-12-17T23:28:39.3707797Z return {} 2024-12-17T23:28:39.3708072Z 2024-12-17T23:28:39.3708330Z return json_response 2024-12-17T23:28:39.3708638Z 2024-12-17T23:28:39.3708645Z 2024-12-17T23:28:39.3709068Z def get_labels(github_repo: str, github_token: str, pr_number: int) -> Set[str]: 2024-12-17T23:28:39.3709923Z """ 2024-12-17T23:28:39.3710503Z Dynamically get the latest list of labels from the pull request 2024-12-17T23:28:39.3711187Z """ 2024-12-17T23:28:39.3711931Z pr_info = get_pr_info(github_repo, github_token, pr_number) 2024-12-17T23:28:39.3712619Z return { 2024-12-17T23:28:39.3713208Z label.get("name") for label in pr_info.get("labels", []) if label.get("name") 2024-12-17T23:28:39.3714031Z } 2024-12-17T23:28:39.3714245Z 2024-12-17T23:28:39.3714251Z 2024-12-17T23:28:39.3714495Z def main() -> None: 2024-12-17T23:28:39.3714933Z args = parse_args() 2024-12-17T23:28:39.3715293Z 2024-12-17T23:28:39.3715542Z runner_label_prefix = DEFAULT_LABEL_PREFIX 2024-12-17T23:28:39.3715981Z 2024-12-17T23:28:39.3716185Z # Check if the PR is opt-out 2024-12-17T23:28:39.3716724Z if args.pr_number: 2024-12-17T23:28:39.3717475Z labels = get_labels(args.github_repo, args.github_token, int(args.pr_number)) 2024-12-17T23:28:39.3718304Z if OPT_OUT_LABEL in labels: 2024-12-17T23:28:39.3718830Z log.info( 2024-12-17T23:28:39.3719599Z f"Opt-out runner determinator because #{args.pr_number} has {OPT_OUT_LABEL} label" 2024-12-17T23:28:39.3720434Z ) 2024-12-17T23:28:39.3721015Z set_github_output(GH_OUTPUT_KEY_LABEL_TYPE, runner_label_prefix) 2024-12-17T23:28:39.3721782Z sys.exit() 2024-12-17T23:28:39.3722108Z 2024-12-17T23:28:39.3722285Z try: 2024-12-17T23:28:39.3722754Z rollout_state = get_rollout_state_from_issue( 2024-12-17T23:28:39.3723593Z args.github_token, args.github_issue_repo, args.github_issue 2024-12-17T23:28:39.3724281Z ) 2024-12-17T23:28:39.3724498Z 2024-12-17T23:28:39.3724740Z username = get_potential_pr_author( 2024-12-17T23:28:39.3725391Z args.github_token, 2024-12-17T23:28:39.3725933Z args.github_repo, 2024-12-17T23:28:39.3726590Z args.github_actor, 2024-12-17T23:28:39.3727186Z args.github_ref_type, 2024-12-17T23:28:39.3727904Z args.github_branch, 2024-12-17T23:28:39.3728417Z ) 2024-12-17T23:28:39.3728707Z 2024-12-17T23:28:39.3729023Z is_canary = args.github_repo == "pytorch/pytorch-canary" 2024-12-17T23:28:39.3729525Z 2024-12-17T23:28:39.3729753Z runner_label_prefix = get_runner_prefix( 2024-12-17T23:28:39.3730362Z rollout_state, 2024-12-17T23:28:39.3730943Z (args.github_issue_owner, username), 2024-12-17T23:28:39.3731544Z args.github_branch, 2024-12-17T23:28:39.3732097Z args.eligible_experiments, 2024-12-17T23:28:39.3732709Z is_canary, 2024-12-17T23:28:39.3733177Z ) 2024-12-17T23:28:39.3733407Z 2024-12-17T23:28:39.3733622Z except Exception as e: 2024-12-17T23:28:39.3734202Z log.error( 2024-12-17T23:28:39.3734902Z f"Failed to get issue. Defaulting to Meta runners and no experiments. Exception: {e}" 2024-12-17T23:28:39.3735721Z ) 2024-12-17T23:28:39.3736006Z 2024-12-17T23:28:39.3736386Z set_github_output(GH_OUTPUT_KEY_LABEL_TYPE, runner_label_prefix) 2024-12-17T23:28:39.3736880Z 2024-12-17T23:28:39.3736887Z 2024-12-17T23:28:39.3737090Z if __name__ == "__main__": 2024-12-17T23:28:39.3737570Z main() 2024-12-17T23:28:39.3737853Z 2024-12-17T23:28:39.3829770Z ##[group]Run python3 -m pip install urllib3==1.26.18 PyGithub==2.3.0 2024-12-17T23:28:39.3830849Z python3 -m pip install urllib3==1.26.18 PyGithub==2.3.0 2024-12-17T23:28:39.3888674Z shell: /usr/bin/bash -e {0} 2024-12-17T23:28:39.3889334Z env: 2024-12-17T23:28:39.3889996Z GITHUB_TOKEN: *** 2024-12-17T23:28:39.3890466Z ISSUE_NUMBER: 5132 2024-12-17T23:28:39.3891061Z TRIGGERING_ACTOR: malfet 2024-12-17T23:28:39.3891541Z ISSUE_OWNER: 2024-12-17T23:28:39.3891995Z CHECK_EXPERIMENTS: 2024-12-17T23:28:39.3892585Z PR_NUMBER: 2024-12-17T23:28:39.3893004Z ##[endgroup] 2024-12-17T23:28:39.7944357Z Defaulting to user installation because normal site-packages is not writeable 2024-12-17T23:28:40.0921285Z Collecting urllib3==1.26.18 2024-12-17T23:28:40.1341828Z Downloading urllib3-1.26.18-py2.py3-none-any.whl (143 kB) 2024-12-17T23:28:40.1697103Z ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 143.8/143.8 KB 6.5 MB/s eta 0:00:00 2024-12-17T23:28:40.1903177Z Collecting PyGithub==2.3.0 2024-12-17T23:28:40.1969804Z Downloading PyGithub-2.3.0-py3-none-any.whl (354 kB) 2024-12-17T23:28:40.2054498Z ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 354.4/354.4 KB 54.5 MB/s eta 0:00:00 2024-12-17T23:28:40.2507155Z Collecting pyjwt[crypto]>=2.4.0 2024-12-17T23:28:40.2547685Z Downloading PyJWT-2.10.1-py3-none-any.whl (22 kB) 2024-12-17T23:28:40.2850987Z Collecting typing-extensions>=4.0.0 2024-12-17T23:28:40.2906957Z Downloading typing_extensions-4.12.2-py3-none-any.whl (37 kB) 2024-12-17T23:28:40.3154246Z Collecting Deprecated 2024-12-17T23:28:40.3198043Z Downloading Deprecated-1.2.15-py2.py3-none-any.whl (9.9 kB) 2024-12-17T23:28:40.3226563Z Requirement already satisfied: requests>=2.14.0 in /usr/lib/python3/dist-packages (from PyGithub==2.3.0) (2.25.1) 2024-12-17T23:28:40.3600376Z Collecting pynacl>=1.4.0 2024-12-17T23:28:40.3658951Z Downloading PyNaCl-1.5.0-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl (856 kB) 2024-12-17T23:28:40.3848906Z ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 856.7/856.7 KB 50.2 MB/s eta 0:00:00 2024-12-17T23:28:40.3975468Z Requirement already satisfied: cryptography>=3.4.0 in /usr/lib/python3/dist-packages (from pyjwt[crypto]>=2.4.0->PyGithub==2.3.0) (3.4.8) 2024-12-17T23:28:40.6282914Z Collecting cffi>=1.4.1 2024-12-17T23:28:40.6321189Z Downloading cffi-1.17.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (446 kB) 2024-12-17T23:28:40.6404891Z ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 446.2/446.2 KB 69.3 MB/s eta 0:00:00 2024-12-17T23:28:40.8294215Z Collecting wrapt<2,>=1.10 2024-12-17T23:28:40.8339599Z Downloading wrapt-1.17.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl (82 kB) 2024-12-17T23:28:40.8381652Z ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 82.7/82.7 KB 32.4 MB/s eta 0:00:00 2024-12-17T23:28:40.8545829Z Collecting pycparser 2024-12-17T23:28:40.8627030Z Downloading pycparser-2.22-py3-none-any.whl (117 kB) 2024-12-17T23:28:40.8671001Z ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 117.6/117.6 KB 46.4 MB/s eta 0:00:00 2024-12-17T23:28:41.0488726Z Installing collected packages: wrapt, urllib3, typing-extensions, pyjwt, pycparser, Deprecated, cffi, pynacl, PyGithub 2024-12-17T23:28:41.5143551Z Successfully installed Deprecated-1.2.15 PyGithub-2.3.0 cffi-1.17.1 pycparser-2.22 pyjwt-2.10.1 pynacl-1.5.0 typing-extensions-4.12.2 urllib3-1.26.18 wrapt-1.17.0 2024-12-17T23:28:41.5936751Z ##[group]Run curr_branch="release/2.6" 2024-12-17T23:28:41.5938333Z curr_branch="release/2.6" 2024-12-17T23:28:41.5939783Z curr_ref_type="branch" 2024-12-17T23:28:41.5941294Z echo "Current branch is '$curr_branch'" 2024-12-17T23:28:41.5942745Z  2024-12-17T23:28:41.5943920Z python3 runner_determinator.py \ 2024-12-17T23:28:41.5945449Z  --github-token "$GITHUB_TOKEN" \ 2024-12-17T23:28:41.5946915Z  --github-issue "$ISSUE_NUMBER" \ 2024-12-17T23:28:41.5948478Z  --github-branch "$curr_branch" \ 2024-12-17T23:28:41.5950006Z  --github-actor "$TRIGGERING_ACTOR" \ 2024-12-17T23:28:41.5951522Z  --github-issue-owner "$ISSUE_OWNER" \ 2024-12-17T23:28:41.5953142Z  --github-ref-type "$curr_ref_type" \ 2024-12-17T23:28:41.5954690Z  --github-repo "$GITHUB_REPOSITORY" \ 2024-12-17T23:28:41.5956335Z  --eligible-experiments "$CHECK_EXPERIMENTS" \ 2024-12-17T23:28:41.5958052Z  --pr-number "${PR_NUMBER}" 2024-12-17T23:28:41.6018793Z shell: /usr/bin/bash -e {0} 2024-12-17T23:28:41.6019982Z env: 2024-12-17T23:28:41.6021419Z GITHUB_TOKEN: *** 2024-12-17T23:28:41.6022792Z ISSUE_NUMBER: 5132 2024-12-17T23:28:41.6024274Z TRIGGERING_ACTOR: malfet 2024-12-17T23:28:41.6025820Z ISSUE_OWNER: 2024-12-17T23:28:41.6027484Z CHECK_EXPERIMENTS: 2024-12-17T23:28:41.6029023Z PR_NUMBER: 2024-12-17T23:28:41.6030654Z ##[endgroup] 2024-12-17T23:28:41.6118939Z Current branch is 'release/2.6' 2024-12-17T23:28:42.8085665Z INFO : Based on rollout percentage of 95%, enabling experiment lf. 2024-12-17T23:28:42.8086922Z INFO : Skipping experiment 'awsa100', as it is not a default experiment 2024-12-17T23:28:42.8087945Z INFO : Setting output: label-type='lf.' 2024-12-17T23:28:42.8381075Z Evaluate and set job outputs 2024-12-17T23:28:42.8388707Z Set output 'label-type' 2024-12-17T23:28:42.8390751Z Cleaning up orphan processes