2024-12-17T23:28:37.2946158Z Current runner version: '2.321.0' 2024-12-17T23:28:37.2970908Z ##[group]Operating System 2024-12-17T23:28:37.2971755Z Ubuntu 2024-12-17T23:28:37.2972357Z 22.04.5 2024-12-17T23:28:37.2972847Z LTS 2024-12-17T23:28:37.2973352Z ##[endgroup] 2024-12-17T23:28:37.2973976Z ##[group]Runner Image 2024-12-17T23:28:37.2974529Z Image: ubuntu-22.04 2024-12-17T23:28:37.2975117Z Version: 20241211.1.0 2024-12-17T23:28:37.2976326Z Included Software: https://github.com/actions/runner-images/blob/ubuntu22/20241211.1/images/ubuntu/Ubuntu2204-Readme.md 2024-12-17T23:28:37.2977870Z Image Release: https://github.com/actions/runner-images/releases/tag/ubuntu22%2F20241211.1 2024-12-17T23:28:37.2978874Z ##[endgroup] 2024-12-17T23:28:37.2979498Z ##[group]Runner Image Provisioner 2024-12-17T23:28:37.2980102Z 2.0.404.1 2024-12-17T23:28:37.2980592Z ##[endgroup] 2024-12-17T23:28:37.2981813Z ##[group]GITHUB_TOKEN Permissions 2024-12-17T23:28:37.2983574Z Contents: read 2024-12-17T23:28:37.2984268Z Metadata: read 2024-12-17T23:28:37.2984965Z Packages: read 2024-12-17T23:28:37.2985670Z ##[endgroup] 2024-12-17T23:28:37.2988464Z Secret source: Actions 2024-12-17T23:28:37.2989790Z Prepare workflow directory 2024-12-17T23:28:37.3471923Z Prepare all required actions 2024-12-17T23:28:37.3525462Z Uses: pytorch/pytorch/.github/workflows/_runner-determinator.yml@refs/heads/release/2.6 (0cdf8b1d09254cfda66191d1bd01e3041c3c76f7) 2024-12-17T23:28:37.3530530Z ##[group] Inputs 2024-12-17T23:28:37.3531164Z check_experiments: 2024-12-17T23:28:37.3531737Z triggering_actor: malfet 2024-12-17T23:28:37.3532352Z issue_owner: 2024-12-17T23:28:37.3532893Z curr_branch: release/2.6 2024-12-17T23:28:37.3533480Z curr_ref_type: branch 2024-12-17T23:28:37.3534042Z issue_number: 5132 2024-12-17T23:28:37.3534589Z ##[endgroup] 2024-12-17T23:28:37.3535209Z Complete job name: get-label-type / runner-determinator 2024-12-17T23:28:37.4167586Z ##[group]Run cat < runner_determinator.py 2024-12-17T23:28:37.4170147Z cat < runner_determinator.py 2024-12-17T23:28:37.4170945Z # flake8: noqa: G004 2024-12-17T23:28:37.4171502Z  2024-12-17T23:28:37.4172264Z # Note: Copies of this script in runner_determinator.py and _runner-determinator.yml 2024-12-17T23:28:37.4173490Z # must be kept in sync. You can do it easily by running the following command: 2024-12-17T23:28:37.4174470Z # python .github/scripts/update_runner_determinator.py 2024-12-17T23:28:37.4175169Z  2024-12-17T23:28:37.4175769Z """ 2024-12-17T23:28:37.4176508Z This runner determinator is used to determine which set of runners to run a 2024-12-17T23:28:37.4177533Z GitHub job on. It uses the first comment of a GitHub issue (by default 2024-12-17T23:28:37.4178909Z https://github.com/pytorch/test-infra/issues/5132) to define the configuration 2024-12-17T23:28:37.4179890Z of which runners should be used to run which job. 2024-12-17T23:28:37.4180688Z  2024-12-17T23:28:37.4181420Z The configuration has two parts, the settings and a list of opted-in users, 2024-12-17T23:28:37.4182555Z separated by a line containing "---". If the line is not present, the 2024-12-17T23:28:37.4183614Z settings are considered to be empty with only the second part, the user 2024-12-17T23:28:37.4184467Z list, defined. 2024-12-17T23:28:37.4185037Z  2024-12-17T23:28:37.4185736Z The first part is a YAML block that defines the rollout settings. This can be 2024-12-17T23:28:37.4186858Z used to define any settings that are needed to determine which runners to use. 2024-12-17T23:28:37.4187995Z It's fields are defined by the RolloutSettings class below. 2024-12-17T23:28:37.4189030Z  2024-12-17T23:28:37.4189865Z The second part is a list of users who are explicitly opted in to the LF fleet. 2024-12-17T23:28:37.4191047Z The user list is also a comma separated list of additional features or 2024-12-17T23:28:37.4192607Z experiments which the user could be opted in to. 2024-12-17T23:28:37.4193343Z  2024-12-17T23:28:37.4193971Z The user list has the following rules: 2024-12-17T23:28:37.4194656Z  2024-12-17T23:28:37.4195289Z - Users are GitHub usernames, which must start with the @ prefix 2024-12-17T23:28:37.4196374Z - Each user is also a comma-separated list of features/experiments to enable 2024-12-17T23:28:37.4197334Z - A "#" prefix opts the user out of all experiments 2024-12-17T23:28:37.4198027Z  2024-12-17T23:28:37.4198562Z Example config: 2024-12-17T23:28:37.4199209Z  # A list of experiments that can be opted into. 2024-12-17T23:28:37.4200103Z  # This defines the behavior they'll induce when opted into. 2024-12-17T23:28:37.4201438Z  # Expected syntax is: 2024-12-17T23:28:37.4202770Z  # [experiment_name]: # Name of the experiment. Also used for the label prefix. 2024-12-17T23:28:37.4204594Z  # rollout_perc: [int] # % of workflows to run with this experiment when users are not opted in. 2024-12-17T23:28:37.4206001Z  2024-12-17T23:28:37.4206552Z  experiments: 2024-12-17T23:28:37.4207116Z  lf: 2024-12-17T23:28:37.4207666Z  rollout_percent: 25 2024-12-17T23:28:37.4208322Z  all_branches: false 2024-12-17T23:28:37.4208959Z  default: true 2024-12-17T23:28:37.4209707Z  --- 2024-12-17T23:28:37.4210241Z  2024-12-17T23:28:37.4210721Z  # Opt-ins: 2024-12-17T23:28:37.4211521Z  # Users can opt into the LF fleet by adding their GitHub username to this list 2024-12-17T23:28:37.4212861Z  # and specifying experiments to enable in a comma-separated list. 2024-12-17T23:28:37.4214076Z  # To always opt out of an experiment, prefix it with a "-". 2024-12-17T23:28:37.4215035Z  # Experiments should be from the above list. 2024-12-17T23:28:37.4215677Z  2024-12-17T23:28:37.4216160Z  @User1,-lf,split_build 2024-12-17T23:28:37.4216832Z  @User2,lf 2024-12-17T23:28:37.4217364Z  @User3,split_build 2024-12-17T23:28:37.4217933Z """ 2024-12-17T23:28:37.4218468Z  2024-12-17T23:28:37.4218889Z import json 2024-12-17T23:28:37.4219403Z import logging 2024-12-17T23:28:37.4220004Z import os 2024-12-17T23:28:37.4220470Z import random 2024-12-17T23:28:37.4221005Z import re 2024-12-17T23:28:37.4221514Z import sys 2024-12-17T23:28:37.4222146Z from argparse import ArgumentParser 2024-12-17T23:28:37.4222829Z from functools import lru_cache 2024-12-17T23:28:37.4223537Z from logging import LogRecord 2024-12-17T23:28:37.4224415Z from typing import Any, Dict, FrozenSet, Iterable, List, NamedTuple, Set, Tuple 2024-12-17T23:28:37.4225363Z from urllib.request import Request, urlopen 2024-12-17T23:28:37.4226095Z  2024-12-17T23:28:37.4226551Z import yaml 2024-12-17T23:28:37.4227071Z from github import Auth, Github 2024-12-17T23:28:37.4227775Z from github.Issue import Issue 2024-12-17T23:28:37.4228393Z  2024-12-17T23:28:37.4229075Z  2024-12-17T23:28:37.4229722Z DEFAULT_LABEL_PREFIX = "" # use meta runners 2024-12-17T23:28:37.4230593Z WORKFLOW_LABEL_LF = "lf." # use runners from the linux foundation 2024-12-17T23:28:37.4231592Z WORKFLOW_LABEL_LF_CANARY = "lf.c." # use canary runners from the linux foundation 2024-12-17T23:28:37.4232554Z  2024-12-17T23:28:37.4233149Z GITHUB_OUTPUT = os.getenv("GITHUB_OUTPUT", "") 2024-12-17T23:28:37.4233851Z GH_OUTPUT_KEY_AMI = "runner-ami" 2024-12-17T23:28:37.4234665Z GH_OUTPUT_KEY_LABEL_TYPE = "label-type" 2024-12-17T23:28:37.4235697Z OPT_OUT_LABEL = "no-runner-experiments" 2024-12-17T23:28:37.4236321Z  2024-12-17T23:28:37.4236938Z SETTING_EXPERIMENTS = "experiments" 2024-12-17T23:28:37.4237575Z  2024-12-17T23:28:37.4238026Z LF_FLEET_EXPERIMENT = "lf" 2024-12-17T23:28:37.4238726Z CANARY_FLEET_SUFFIX = ".c" 2024-12-17T23:28:37.4239319Z  2024-12-17T23:28:37.4239740Z  2024-12-17T23:28:37.4240490Z class Experiment(NamedTuple): 2024-12-17T23:28:37.4241137Z  rollout_perc: float = ( 2024-12-17T23:28:37.4241965Z  0 # Percentage of workflows to experiment on when user is not opted-in. 2024-12-17T23:28:37.4242879Z  ) 2024-12-17T23:28:37.4243410Z  all_branches: bool = ( 2024-12-17T23:28:37.4244232Z  False # If True, the experiment is also enabled on the exception branches 2024-12-17T23:28:37.4245137Z  ) 2024-12-17T23:28:37.4245639Z  default: bool = ( 2024-12-17T23:28:37.4246411Z  True # If True, the experiment is enabled by default for all queries 2024-12-17T23:28:37.4247255Z  ) 2024-12-17T23:28:37.4247739Z  2024-12-17T23:28:37.4248233Z  # Add more fields as needed 2024-12-17T23:28:37.4248894Z  2024-12-17T23:28:37.4249355Z  2024-12-17T23:28:37.4249840Z class Settings(NamedTuple): 2024-12-17T23:28:37.4250487Z  """ 2024-12-17T23:28:37.4251108Z  Settings for the experiments that can be opted into. 2024-12-17T23:28:37.4251841Z  """ 2024-12-17T23:28:37.4252403Z  2024-12-17T23:28:37.4252933Z  experiments: Dict[str, Experiment] = {} 2024-12-17T23:28:37.4253592Z  2024-12-17T23:28:37.4254101Z  2024-12-17T23:28:37.4254863Z class ColorFormatter(logging.Formatter): 2024-12-17T23:28:37.4255679Z  """Color codes the log messages based on the log level""" 2024-12-17T23:28:37.4256481Z  2024-12-17T23:28:37.4256966Z  COLORS = { 2024-12-17T23:28:37.4257523Z  "WARNING": "\033[33m", # Yellow 2024-12-17T23:28:37.4258227Z  "ERROR": "\033[31m", # Red 2024-12-17T23:28:37.4258901Z  "CRITICAL": "\033[31m", # Red 2024-12-17T23:28:37.4259665Z  "INFO": "\033[0m", # Reset 2024-12-17T23:28:37.4260357Z  "DEBUG": "\033[0m", # Reset 2024-12-17T23:28:37.4261025Z  } 2024-12-17T23:28:37.4261487Z  2024-12-17T23:28:37.4262220Z  def format(self, record: LogRecord) -> str: 2024-12-17T23:28:37.4264372Z  log_color = self.COLORS.get(record.levelname, "\033[0m") # Default to reset 2024-12-17T23:28:37.4265920Z  record.msg = f"{log_color}{record.msg}\033[0m" 2024-12-17T23:28:37.4266784Z  return super().format(record) 2024-12-17T23:28:37.4267564Z  2024-12-17T23:28:37.4268074Z  2024-12-17T23:28:37.4268671Z handler = logging.StreamHandler() 2024-12-17T23:28:37.4270009Z handler.setFormatter(ColorFormatter(fmt="%(levelname)-8s: %(message)s")) 2024-12-17T23:28:37.4270911Z  2024-12-17T23:28:37.4271494Z log = logging.getLogger(os.path.basename(__file__)) 2024-12-17T23:28:37.4272313Z log.addHandler(handler) 2024-12-17T23:28:37.4272932Z log.setLevel(logging.INFO) 2024-12-17T23:28:37.4273483Z  2024-12-17T23:28:37.4273995Z  2024-12-17T23:28:37.4274610Z def set_github_output(key: str, value: str) -> None: 2024-12-17T23:28:37.4275290Z  """ 2024-12-17T23:28:37.4276066Z  Defines outputs of the github action that invokes this script 2024-12-17T23:28:37.4276843Z  """ 2024-12-17T23:28:37.4277324Z  if not GITHUB_OUTPUT: 2024-12-17T23:28:37.4278651Z  # See https://github.blog/changelog/2022-10-11-github-actions-deprecating-save-state-and-set-output-commands/ for deprecation notice 2024-12-17T23:28:37.4280163Z  log.warning( 2024-12-17T23:28:37.4281157Z  "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:37.4282363Z  ) 2024-12-17T23:28:37.4282949Z  print(f"::set-output name={key}::{value}") 2024-12-17T23:28:37.4283624Z  return 2024-12-17T23:28:37.4284280Z  2024-12-17T23:28:37.4284803Z  with open(GITHUB_OUTPUT, "a") as f: 2024-12-17T23:28:37.4285527Z  log.info(f"Setting output: {key}='{value}'") 2024-12-17T23:28:37.4286312Z  f.write(f"{key}={value}\n") 2024-12-17T23:28:37.4287063Z  2024-12-17T23:28:37.4287545Z  2024-12-17T23:28:37.4288281Z def _str_comma_separated_to_set(value: str) -> FrozenSet[str]: 2024-12-17T23:28:37.4289126Z  return frozenset( 2024-12-17T23:28:37.4289979Z  filter(lambda itm: itm != "", map(str.strip, value.strip(" \n\t").split(","))) 2024-12-17T23:28:37.4290886Z  ) 2024-12-17T23:28:37.4291370Z  2024-12-17T23:28:37.4291826Z  2024-12-17T23:28:37.4292368Z def parse_args() -> Any: 2024-12-17T23:28:37.4293112Z  parser = ArgumentParser("Get dynamic rollout settings") 2024-12-17T23:28:37.4294163Z  parser.add_argument("--github-token", type=str, required=True, help="GitHub token") 2024-12-17T23:28:37.4295188Z  parser.add_argument( 2024-12-17T23:28:37.4295775Z  "--github-issue-repo", 2024-12-17T23:28:37.4296398Z  type=str, 2024-12-17T23:28:37.4297157Z  required=False, 2024-12-17T23:28:37.4297987Z  default="pytorch/test-infra", 2024-12-17T23:28:37.4298817Z  help="GitHub repo to get the issue", 2024-12-17T23:28:37.4299573Z  ) 2024-12-17T23:28:37.4300079Z  parser.add_argument( 2024-12-17T23:28:37.4300683Z  "--github-repo", 2024-12-17T23:28:37.4301430Z  type=str, 2024-12-17T23:28:37.4302330Z  required=True, 2024-12-17T23:28:37.4303243Z  help="GitHub repo where CI is running", 2024-12-17T23:28:37.4304011Z  ) 2024-12-17T23:28:37.4304494Z  parser.add_argument( 2024-12-17T23:28:37.4305254Z  "--github-issue", type=int, required=True, help="GitHub issue number" 2024-12-17T23:28:37.4306137Z  ) 2024-12-17T23:28:37.4306601Z  parser.add_argument( 2024-12-17T23:28:37.4307390Z  "--github-actor", type=str, required=True, help="GitHub triggering_actor" 2024-12-17T23:28:37.4308290Z  ) 2024-12-17T23:28:37.4309103Z  parser.add_argument( 2024-12-17T23:28:37.4309956Z  "--github-issue-owner", type=str, required=True, help="GitHub issue owner" 2024-12-17T23:28:37.4310918Z  ) 2024-12-17T23:28:37.4311376Z  parser.add_argument( 2024-12-17T23:28:37.4312183Z  "--github-branch", type=str, required=True, help="Current GitHub branch or tag" 2024-12-17T23:28:37.4313110Z  ) 2024-12-17T23:28:37.4313597Z  parser.add_argument( 2024-12-17T23:28:37.4314145Z  "--github-ref-type", 2024-12-17T23:28:37.4314825Z  type=str, 2024-12-17T23:28:37.4315365Z  required=True, 2024-12-17T23:28:37.4316083Z  help="Current GitHub ref type, branch or tag", 2024-12-17T23:28:37.4316782Z  ) 2024-12-17T23:28:37.4317258Z  parser.add_argument( 2024-12-17T23:28:37.4317923Z  "--eligible-experiments", 2024-12-17T23:28:37.4318602Z  type=_str_comma_separated_to_set, 2024-12-17T23:28:37.4319214Z  required=False, 2024-12-17T23:28:37.4320101Z  default="", 2024-12-17T23:28:37.4322047Z  help="comma separated list of experiments to check, if omitted all experiments marked with default=True are checked", 2024-12-17T23:28:37.4323599Z  ) 2024-12-17T23:28:37.4324230Z  parser.add_argument( 2024-12-17T23:28:37.4324828Z  "--pr-number", 2024-12-17T23:28:37.4325369Z  type=str, 2024-12-17T23:28:37.4325998Z  required=False, 2024-12-17T23:28:37.4326577Z  default="", 2024-12-17T23:28:37.4327209Z  help="the optional PR number where this is run", 2024-12-17T23:28:37.4327968Z  ) 2024-12-17T23:28:37.4328441Z  2024-12-17T23:28:37.4328898Z  return parser.parse_args() 2024-12-17T23:28:37.4329584Z  2024-12-17T23:28:37.4330064Z  2024-12-17T23:28:37.4330573Z def get_gh_client(github_token: str) -> Github: 2024-12-17T23:28:37.4331381Z  auth = Auth.Token(github_token) 2024-12-17T23:28:37.4332042Z  return Github(auth=auth) 2024-12-17T23:28:37.4332571Z  2024-12-17T23:28:37.4333099Z  2024-12-17T23:28:37.4333760Z def get_issue(gh: Github, repo: str, issue_num: int) -> Issue: 2024-12-17T23:28:37.4334500Z  repo = gh.get_repo(repo) 2024-12-17T23:28:37.4335229Z  return repo.get_issue(number=issue_num) 2024-12-17T23:28:37.4335887Z  2024-12-17T23:28:37.4336369Z  2024-12-17T23:28:37.4336830Z def get_potential_pr_author( 2024-12-17T23:28:37.4337644Z  github_token: str, repo: str, username: str, ref_type: str, ref_name: str 2024-12-17T23:28:37.4338499Z ) -> str: 2024-12-17T23:28:37.4339144Z  # If the trigger was a new tag added by a bot, this is a ciflow case 2024-12-17T23:28:37.4340259Z  # Fetch the actual username from the original PR. The PR number is 2024-12-17T23:28:37.4341240Z  # embedded in the tag name: ciflow// 2024-12-17T23:28:37.4341944Z  2024-12-17T23:28:37.4342735Z  gh = get_gh_client(github_token) 2024-12-17T23:28:37.4343793Z  2024-12-17T23:28:37.4344695Z  if username == "pytorch-bot[bot]" and ref_type == "tag": 2024-12-17T23:28:37.4345882Z  split_tag = ref_name.split("/") 2024-12-17T23:28:37.4346592Z  if ( 2024-12-17T23:28:37.4347114Z  len(split_tag) == 3 2024-12-17T23:28:37.4347749Z  and split_tag[0] == "ciflow" 2024-12-17T23:28:37.4348491Z  and split_tag[2].isnumeric() 2024-12-17T23:28:37.4349427Z  ): 2024-12-17T23:28:37.4349933Z  pr_number = split_tag[2] 2024-12-17T23:28:37.4350639Z  try: 2024-12-17T23:28:37.4351274Z  repository = gh.get_repo(repo) 2024-12-17T23:28:37.4352002Z  pull = repository.get_pull(number=int(pr_number)) 2024-12-17T23:28:37.4352825Z  except Exception as e: 2024-12-17T23:28:37.4353506Z  raise Exception( # noqa: TRY002 2024-12-17T23:28:37.4354270Z  f"issue with pull request {pr_number} from repo {repository}" 2024-12-17T23:28:37.4355099Z  ) from e 2024-12-17T23:28:37.4355715Z  return pull.user.login 2024-12-17T23:28:37.4356407Z  # In all other cases, return the original input username 2024-12-17T23:28:37.4357186Z  return username 2024-12-17T23:28:37.4357739Z  2024-12-17T23:28:37.4358166Z  2024-12-17T23:28:37.4358757Z def is_exception_branch(branch: str) -> bool: 2024-12-17T23:28:37.4359430Z  """ 2024-12-17T23:28:37.4360241Z  Branches that get opted out of experiments by default, until they're explicitly enabled. 2024-12-17T23:28:37.4361141Z  """ 2024-12-17T23:28:37.4362056Z  return branch.split("/")[0] in {"main", "nightly", "release", "landchecks"} 2024-12-17T23:28:37.4362834Z  2024-12-17T23:28:37.4363298Z  2024-12-17T23:28:37.4363833Z def load_yaml(yaml_text: str) -> Any: 2024-12-17T23:28:37.4364458Z  try: 2024-12-17T23:28:37.4364991Z  data = yaml.safe_load(yaml_text) 2024-12-17T23:28:37.4365653Z  return data 2024-12-17T23:28:37.4366215Z  except yaml.YAMLError: 2024-12-17T23:28:37.4366865Z  log.exception("Error loading YAML") 2024-12-17T23:28:37.4367546Z  raise 2024-12-17T23:28:37.4368050Z  2024-12-17T23:28:37.4368509Z  2024-12-17T23:28:37.4369273Z def extract_settings_user_opt_in_from_text(rollout_state: str) -> Tuple[str, str]: 2024-12-17T23:28:37.4370136Z  """ 2024-12-17T23:28:37.4370902Z  Extracts the text with settings, if any, and the opted in users from the rollout state. 2024-12-17T23:28:37.4371806Z  2024-12-17T23:28:37.4372462Z  If the issue body contains "---" then the text above that is the settings 2024-12-17T23:28:37.4373436Z  and the text below is the list of opted in users. 2024-12-17T23:28:37.4374085Z  2024-12-17T23:28:37.4374771Z  If it doesn't contain "---" then the settings are empty and the rest is the users. 2024-12-17T23:28:37.4375722Z  """ 2024-12-17T23:28:37.4376273Z  rollout_state_parts = rollout_state.split("---") 2024-12-17T23:28:37.4376991Z  if len(rollout_state_parts) >= 2: 2024-12-17T23:28:37.4377822Z  return rollout_state_parts[0], rollout_state_parts[1] 2024-12-17T23:28:37.4378503Z  else: 2024-12-17T23:28:37.4379178Z  return "", rollout_state 2024-12-17T23:28:37.4379850Z  2024-12-17T23:28:37.4380258Z  2024-12-17T23:28:37.4380779Z class UserOptins(Dict[str, List[str]]): 2024-12-17T23:28:37.4381480Z  """ 2024-12-17T23:28:37.4382103Z  Dictionary of users with a list of features they have opted into 2024-12-17T23:28:37.4382889Z  """ 2024-12-17T23:28:37.4383425Z  2024-12-17T23:28:37.4383829Z  2024-12-17T23:28:37.4384476Z def parse_user_opt_in_from_text(user_optin_text: str) -> UserOptins: 2024-12-17T23:28:37.4385301Z  """ 2024-12-17T23:28:37.4386100Z  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:37.4387056Z  2024-12-17T23:28:37.4388027Z  Users are GitHub usernames with the @ prefix. Each user is also a comma-separated list of features/experiments to enable. 2024-12-17T23:28:37.4389524Z  - Example line: "@User1,lf,split_build" 2024-12-17T23:28:37.4390316Z  - A "#" prefix indicates the user is opted out of all experiments 2024-12-17T23:28:37.4391261Z  2024-12-17T23:28:37.4391724Z  2024-12-17T23:28:37.4392129Z  """ 2024-12-17T23:28:37.4392701Z  optins = UserOptins() 2024-12-17T23:28:37.4393360Z  for user in user_optin_text.split("\n"): 2024-12-17T23:28:37.4394004Z  user = user.strip("\r\n\t -") 2024-12-17T23:28:37.4394746Z  if not user or not user.startswith("@"): 2024-12-17T23:28:37.4395445Z  # Not a valid user. Skip 2024-12-17T23:28:37.4396024Z  continue 2024-12-17T23:28:37.4396627Z  2024-12-17T23:28:37.4397223Z  if user: 2024-12-17T23:28:37.4398080Z  usr_name = user.split(",")[0].strip("@") 2024-12-17T23:28:37.4399454Z  optins[usr_name] = [exp.strip(" ") for exp in user.split(",")[1:]] 2024-12-17T23:28:37.4400227Z  2024-12-17T23:28:37.4400691Z  return optins 2024-12-17T23:28:37.4401281Z  2024-12-17T23:28:37.4401922Z  2024-12-17T23:28:37.4402530Z def is_valid_experiment_name(experiment_name: str) -> bool: 2024-12-17T23:28:37.4403485Z  """ 2024-12-17T23:28:37.4404024Z  Check if the experiment name is valid. 2024-12-17T23:28:37.4404661Z  A valid name: 2024-12-17T23:28:37.4405513Z  - Contains only alphanumeric characters and the special characters "_" & "-" 2024-12-17T23:28:37.4406564Z  - The special characters "_" & "-" shouldn't be the first or last characters 2024-12-17T23:28:37.4407399Z  - Cannot contain spaces 2024-12-17T23:28:37.4408028Z  """ 2024-12-17T23:28:37.4408506Z  2024-12-17T23:28:37.4409085Z  valid_char_regex = r"^[a-zA-Z0-9]([\w-]*[a-zA-Z0-9])?$" 2024-12-17T23:28:37.4409956Z  valid = bool(re.match(valid_char_regex, experiment_name)) 2024-12-17T23:28:37.4410679Z  2024-12-17T23:28:37.4411107Z  if valid: 2024-12-17T23:28:37.4411703Z  return True 2024-12-17T23:28:37.4412212Z  2024-12-17T23:28:37.4412645Z  log.error( 2024-12-17T23:28:37.4414262Z  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:37.4415851Z  ) 2024-12-17T23:28:37.4416309Z  return False 2024-12-17T23:28:37.4416899Z  2024-12-17T23:28:37.4417336Z  2024-12-17T23:28:37.4417935Z def parse_settings_from_text(settings_text: str) -> Settings: 2024-12-17T23:28:37.4418778Z  """ 2024-12-17T23:28:37.4419606Z  Parse the experiments from the issue body into a list of ExperimentSettings 2024-12-17T23:28:37.4420425Z  """ 2024-12-17T23:28:37.4420997Z  try: 2024-12-17T23:28:37.4421466Z  if settings_text: 2024-12-17T23:28:37.4422326Z  # Escape the backtick as well so that we can have the settings in a code block on the GH issue 2024-12-17T23:28:37.4423315Z  # for easy reading 2024-12-17T23:28:37.4424239Z  # Note: Using ascii for the backtick so that the cat step in _runner-determinator.yml doesn't choke on 2024-12-17T23:28:37.4425640Z  # the backtick character in shell commands. 2024-12-17T23:28:37.4426442Z  backtick = chr(96) # backtick character 2024-12-17T23:28:37.4427299Z  settings_text = settings_text.strip(f"\r\n\t{backtick} ") 2024-12-17T23:28:37.4428079Z  settings = load_yaml(settings_text) 2024-12-17T23:28:37.4429207Z  2024-12-17T23:28:37.4430130Z  # For now we just load experiments. We can expand this if/when we add more settings 2024-12-17T23:28:37.4431572Z  experiments = {} 2024-12-17T23:28:37.4432417Z  2024-12-17T23:28:37.4433167Z  for exp_name, exp_settings in settings.get(SETTING_EXPERIMENTS).items(): 2024-12-17T23:28:37.4434087Z  if not is_valid_experiment_name(exp_name): 2024-12-17T23:28:37.4435266Z  # 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:37.4436442Z  continue 2024-12-17T23:28:37.4437035Z  2024-12-17T23:28:37.4437505Z  valid_settings = {} 2024-12-17T23:28:37.4438219Z  for setting in exp_settings: 2024-12-17T23:28:37.4438934Z  if setting not in Experiment._fields: 2024-12-17T23:28:37.4439621Z  log.warning( 2024-12-17T23:28:37.4440484Z  f"Unexpected setting in experiment: {setting} = {exp_settings[setting]}" 2024-12-17T23:28:37.4441528Z  ) 2024-12-17T23:28:37.4442104Z  else: 2024-12-17T23:28:37.4442797Z  valid_settings[setting] = exp_settings[setting] 2024-12-17T23:28:37.4443505Z  2024-12-17T23:28:37.4444105Z  experiments[exp_name] = Experiment(**valid_settings) 2024-12-17T23:28:37.4444906Z  return Settings(experiments) 2024-12-17T23:28:37.4445573Z  2024-12-17T23:28:37.4446057Z  except Exception: 2024-12-17T23:28:37.4446707Z  log.exception("Failed to parse settings") 2024-12-17T23:28:37.4447386Z  2024-12-17T23:28:37.4447862Z  return Settings() 2024-12-17T23:28:37.4448422Z  2024-12-17T23:28:37.4448885Z  2024-12-17T23:28:37.4449467Z def parse_settings(rollout_state: str) -> Settings: 2024-12-17T23:28:37.4450238Z  """ 2024-12-17T23:28:37.4450796Z  Parse settings, if any, from the rollout state. 2024-12-17T23:28:37.4451457Z  2024-12-17T23:28:37.4452179Z  If the issue body contains "---" then the text above that is the settings 2024-12-17T23:28:37.4453068Z  and the text below is the list of opted in users. 2024-12-17T23:28:37.4453732Z  2024-12-17T23:28:37.4454510Z  If it doesn't contain "---" then the settings are empty and the default values are used. 2024-12-17T23:28:37.4455345Z  """ 2024-12-17T23:28:37.4456035Z  settings_text, _ = extract_settings_user_opt_in_from_text(rollout_state) 2024-12-17T23:28:37.4457000Z  return parse_settings_from_text(settings_text) 2024-12-17T23:28:37.4457650Z  2024-12-17T23:28:37.4458265Z  2024-12-17T23:28:37.4458945Z def parse_users(rollout_state: str) -> UserOptins: 2024-12-17T23:28:37.4459601Z  """ 2024-12-17T23:28:37.4460127Z  Parse users from the rollout state. 2024-12-17T23:28:37.4460842Z  2024-12-17T23:28:37.4461253Z  """ 2024-12-17T23:28:37.4461924Z  _, users_text = extract_settings_user_opt_in_from_text(rollout_state) 2024-12-17T23:28:37.4462887Z  return parse_user_opt_in_from_text(users_text) 2024-12-17T23:28:37.4463551Z  2024-12-17T23:28:37.4463960Z  2024-12-17T23:28:37.4464778Z def is_user_opted_in(user: str, user_optins: UserOptins, experiment_name: str) -> bool: 2024-12-17T23:28:37.4465647Z  """ 2024-12-17T23:28:37.4466179Z  Check if a user is opted into an experiment 2024-12-17T23:28:37.4466896Z  """ 2024-12-17T23:28:37.4467499Z  return experiment_name in user_optins.get(user, []) 2024-12-17T23:28:37.4468176Z  2024-12-17T23:28:37.4468921Z  2024-12-17T23:28:37.4469771Z def is_user_opted_out(user: str, user_optins: UserOptins, experiment_name: str) -> bool: 2024-12-17T23:28:37.4470647Z  """ 2024-12-17T23:28:37.4471335Z  Check if a user explicitly opted out of an experiment 2024-12-17T23:28:37.4472031Z  """ 2024-12-17T23:28:37.4472653Z  # if the experiment is prefixed with a "-", then it's an opt-out 2024-12-17T23:28:37.4473555Z  experiment_optout = "-" + experiment_name 2024-12-17T23:28:37.4474346Z  if experiment_optout not in user_optins.get(user, []): 2024-12-17T23:28:37.4475052Z  return False 2024-12-17T23:28:37.4475667Z  2024-12-17T23:28:37.4476263Z  if is_user_opted_in(user, user_optins, experiment_name): 2024-12-17T23:28:37.4476965Z  log.warning( 2024-12-17T23:28:37.4477965Z  f"User {user} is opted into experiment {experiment_name}, but also opted out of it. Defaulting to opting out" 2024-12-17T23:28:37.4478973Z  ) 2024-12-17T23:28:37.4479626Z  2024-12-17T23:28:37.4480127Z  return True 2024-12-17T23:28:37.4480670Z  2024-12-17T23:28:37.4481094Z  2024-12-17T23:28:37.4481620Z def get_runner_prefix( 2024-12-17T23:28:37.4482197Z  rollout_state: str, 2024-12-17T23:28:37.4482800Z  workflow_requestors: Iterable[str], 2024-12-17T23:28:37.4483497Z  branch: str, 2024-12-17T23:28:37.4484145Z  eligible_experiments: FrozenSet[str] = frozenset(), 2024-12-17T23:28:37.4484859Z  is_canary: bool = False, 2024-12-17T23:28:37.4485494Z ) -> str: 2024-12-17T23:28:37.4486048Z  settings = parse_settings(rollout_state) 2024-12-17T23:28:37.4486748Z  user_optins = parse_users(rollout_state) 2024-12-17T23:28:37.4487449Z  2024-12-17T23:28:37.4487912Z  fleet_prefix = "" 2024-12-17T23:28:37.4488453Z  prefixes = [] 2024-12-17T23:28:37.4489300Z  for experiment_name, experiment_settings in settings.experiments.items(): 2024-12-17T23:28:37.4490395Z  if not experiment_settings.all_branches and is_exception_branch(branch): 2024-12-17T23:28:37.4491229Z  log.info( 2024-12-17T23:28:37.4492132Z  f"Branch {branch} is an exception branch. Not enabling experiment {experiment_name}." 2024-12-17T23:28:37.4492963Z  ) 2024-12-17T23:28:37.4493485Z  continue 2024-12-17T23:28:37.4494085Z  2024-12-17T23:28:37.4494531Z  if eligible_experiments: 2024-12-17T23:28:37.4495235Z  if experiment_name not in eligible_experiments: 2024-12-17T23:28:37.4496076Z  exp_list = ", ".join(eligible_experiments) 2024-12-17T23:28:37.4496959Z  log.info( 2024-12-17T23:28:37.4498472Z  f"Skipping experiment '{experiment_name}', as it is not in the eligible_experiments list: {exp_list}" 2024-12-17T23:28:37.4500186Z  ) 2024-12-17T23:28:37.4501086Z  continue 2024-12-17T23:28:37.4502129Z  elif not experiment_settings.default: 2024-12-17T23:28:37.4503194Z  log.info( 2024-12-17T23:28:37.4504672Z  f"Skipping experiment '{experiment_name}', as it is not a default experiment" 2024-12-17T23:28:37.4505971Z  ) 2024-12-17T23:28:37.4506775Z  continue 2024-12-17T23:28:37.4507516Z  2024-12-17T23:28:37.4508067Z  # Is any workflow_requestor opted out to this experiment? 2024-12-17T23:28:37.4509524Z  opted_out_users = [ 2024-12-17T23:28:37.4510254Z  requestor 2024-12-17T23:28:37.4510901Z  for requestor in workflow_requestors 2024-12-17T23:28:37.4511666Z  if is_user_opted_out(requestor, user_optins, experiment_name) 2024-12-17T23:28:37.4512486Z  ] 2024-12-17T23:28:37.4512970Z  2024-12-17T23:28:37.4513407Z  if opted_out_users: 2024-12-17T23:28:37.4514056Z  log.info( 2024-12-17T23:28:37.4514845Z  f"{', '.join(opted_out_users)} have opted out of experiment {experiment_name}." 2024-12-17T23:28:37.4515609Z  ) 2024-12-17T23:28:37.4516180Z  continue 2024-12-17T23:28:37.4516719Z  2024-12-17T23:28:37.4517255Z  # Is any workflow_requestor opted in to this experiment? 2024-12-17T23:28:37.4518078Z  opted_in_users = [ 2024-12-17T23:28:37.4518670Z  requestor 2024-12-17T23:28:37.4519239Z  for requestor in workflow_requestors 2024-12-17T23:28:37.4520327Z  if is_user_opted_in(requestor, user_optins, experiment_name) 2024-12-17T23:28:37.4521073Z  ] 2024-12-17T23:28:37.4521726Z  2024-12-17T23:28:37.4522262Z  enabled = False 2024-12-17T23:28:37.4523077Z  if opted_in_users: 2024-12-17T23:28:37.4523681Z  log.info( 2024-12-17T23:28:37.4525055Z  f"{', '.join(opted_in_users)} have opted into experiment {experiment_name}." 2024-12-17T23:28:37.4526176Z  ) 2024-12-17T23:28:37.4526766Z  enabled = True 2024-12-17T23:28:37.4527332Z  2024-12-17T23:28:37.4527845Z  elif experiment_settings.rollout_perc: 2024-12-17T23:28:37.4528849Z  # If no user is opted in, then we randomly enable the experiment based on the rollout percentage 2024-12-17T23:28:37.4529900Z  if random.uniform(0, 100) <= experiment_settings.rollout_perc: 2024-12-17T23:28:37.4530654Z  log.info( 2024-12-17T23:28:37.4531707Z  f"Based on rollout percentage of {experiment_settings.rollout_perc}%, enabling experiment {experiment_name}." 2024-12-17T23:28:37.4532751Z  ) 2024-12-17T23:28:37.4533258Z  enabled = True 2024-12-17T23:28:37.4533905Z  2024-12-17T23:28:37.4534375Z  if enabled: 2024-12-17T23:28:37.4534910Z  label = experiment_name 2024-12-17T23:28:37.4535654Z  if experiment_name == LF_FLEET_EXPERIMENT: 2024-12-17T23:28:37.4536624Z  # We give some special treatment to the "lf" experiment since determines the fleet we use 2024-12-17T23:28:37.4537586Z  # - If it's enabled, then we always list it's prefix first 2024-12-17T23:28:37.4538709Z  # - If we're in the canary branch, then we append ".c" to the lf prefix 2024-12-17T23:28:37.4539528Z  if is_canary: 2024-12-17T23:28:37.4540187Z  label += CANARY_FLEET_SUFFIX 2024-12-17T23:28:37.4540875Z  fleet_prefix = label 2024-12-17T23:28:37.4541506Z  else: 2024-12-17T23:28:37.4542089Z  prefixes.append(label) 2024-12-17T23:28:37.4542706Z  2024-12-17T23:28:37.4543200Z  if len(prefixes) > 1: 2024-12-17T23:28:37.4543775Z  log.error( 2024-12-17T23:28:37.4545057Z  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:37.4546320Z  ) 2024-12-17T23:28:37.4546837Z  prefixes = prefixes[:1] 2024-12-17T23:28:37.4547434Z  2024-12-17T23:28:37.4547993Z  # Fleet always comes first 2024-12-17T23:28:37.4548596Z  if fleet_prefix: 2024-12-17T23:28:37.4549579Z  prefixes.insert(0, fleet_prefix) 2024-12-17T23:28:37.4550202Z  2024-12-17T23:28:37.4550766Z  return ".".join(prefixes) + "." if prefixes else "" 2024-12-17T23:28:37.4551522Z  2024-12-17T23:28:37.4551927Z  2024-12-17T23:28:37.4552698Z def get_rollout_state_from_issue(github_token: str, repo: str, issue_num: int) -> str: 2024-12-17T23:28:37.4553684Z  """ 2024-12-17T23:28:37.4554380Z  Gets the first comment of the issue, which contains the desired rollout state. 2024-12-17T23:28:37.4555227Z  2024-12-17T23:28:37.4556013Z  The default issue we use - https://github.com/pytorch/test-infra/issues/5132 2024-12-17T23:28:37.4556836Z  """ 2024-12-17T23:28:37.4557359Z  gh = get_gh_client(github_token) 2024-12-17T23:28:37.4558130Z  issue = get_issue(gh, repo, issue_num) 2024-12-17T23:28:37.4558893Z  return str(issue.get_comments()[0].body.strip("\n\t ")) 2024-12-17T23:28:37.4559618Z  2024-12-17T23:28:37.4560146Z  2024-12-17T23:28:37.4561024Z def download_json(url: str, headers: Dict[str, str], num_retries: int = 3) -> Any: 2024-12-17T23:28:37.4561947Z  for _ in range(num_retries): 2024-12-17T23:28:37.4562625Z  try: 2024-12-17T23:28:37.4563194Z  req = Request(url=url, headers=headers) 2024-12-17T23:28:37.4563961Z  content = urlopen(req, timeout=5).read().decode("utf-8") 2024-12-17T23:28:37.4564796Z  return json.loads(content) 2024-12-17T23:28:37.4565444Z  except Exception as e: 2024-12-17T23:28:37.4566111Z  log.warning(f"Could not download {url}: {e}") 2024-12-17T23:28:37.4566839Z  2024-12-17T23:28:37.4567544Z  log.warning(f"All {num_retries} retries exhausted, downloading {url} failed") 2024-12-17T23:28:37.4568338Z  return {} 2024-12-17T23:28:37.4568901Z  2024-12-17T23:28:37.4569385Z  2024-12-17T23:28:37.4569818Z @lru_cache(maxsize=None) 2024-12-17T23:28:37.4570729Z def get_pr_info(github_repo: str, github_token: str, pr_number: int) -> Dict[str, Any]: 2024-12-17T23:28:37.4571608Z  """ 2024-12-17T23:28:37.4572087Z  Dynamically get PR information 2024-12-17T23:28:37.4572764Z  """ 2024-12-17T23:28:37.4573406Z  github_api = f"https://api.github.com/repos/{github_repo}" 2024-12-17T23:28:37.4574131Z  headers = { 2024-12-17T23:28:37.4574769Z  "Accept": "application/vnd.github.v3+json", 2024-12-17T23:28:37.4575560Z  "Authorization": f"token {github_token}", 2024-12-17T23:28:37.4576186Z  } 2024-12-17T23:28:37.4576781Z  json_response: Dict[str, Any] = download_json( 2024-12-17T23:28:37.4577666Z  url=f"{github_api}/issues/{pr_number}", 2024-12-17T23:28:37.4578320Z  headers=headers, 2024-12-17T23:28:37.4578943Z  ) 2024-12-17T23:28:37.4579420Z  2024-12-17T23:28:37.4579864Z  if not json_response: 2024-12-17T23:28:37.4580644Z  log.warning(f"Failed to get the labels for #{pr_number}") 2024-12-17T23:28:37.4581383Z  return {} 2024-12-17T23:28:37.4581893Z  2024-12-17T23:28:37.4582417Z  return json_response 2024-12-17T23:28:37.4582976Z  2024-12-17T23:28:37.4583438Z  2024-12-17T23:28:37.4584206Z def get_labels(github_repo: str, github_token: str, pr_number: int) -> Set[str]: 2024-12-17T23:28:37.4585039Z  """ 2024-12-17T23:28:37.4585703Z  Dynamically get the latest list of labels from the pull request 2024-12-17T23:28:37.4586507Z  """ 2024-12-17T23:28:37.4587124Z  pr_info = get_pr_info(github_repo, github_token, pr_number) 2024-12-17T23:28:37.4587852Z  return { 2024-12-17T23:28:37.4588638Z  label.get("name") for label in pr_info.get("labels", []) if label.get("name") 2024-12-17T23:28:37.4589774Z  } 2024-12-17T23:28:37.4590245Z  2024-12-17T23:28:37.4590781Z  2024-12-17T23:28:37.4591202Z def main() -> None: 2024-12-17T23:28:37.4591756Z  args = parse_args() 2024-12-17T23:28:37.4592377Z  2024-12-17T23:28:37.4592884Z  runner_label_prefix = DEFAULT_LABEL_PREFIX 2024-12-17T23:28:37.4593520Z  2024-12-17T23:28:37.4594063Z  # Check if the PR is opt-out 2024-12-17T23:28:37.4594659Z  if args.pr_number: 2024-12-17T23:28:37.4595825Z  labels = get_labels(args.github_repo, args.github_token, int(args.pr_number)) 2024-12-17T23:28:37.4597445Z  if OPT_OUT_LABEL in labels: 2024-12-17T23:28:37.4598308Z  log.info( 2024-12-17T23:28:37.4599208Z  f"Opt-out runner determinator because #{args.pr_number} has {OPT_OUT_LABEL} label" 2024-12-17T23:28:37.4600197Z  ) 2024-12-17T23:28:37.4601081Z  set_github_output(GH_OUTPUT_KEY_LABEL_TYPE, runner_label_prefix) 2024-12-17T23:28:37.4601850Z  sys.exit() 2024-12-17T23:28:37.4602495Z  2024-12-17T23:28:37.4602914Z  try: 2024-12-17T23:28:37.4603465Z  rollout_state = get_rollout_state_from_issue( 2024-12-17T23:28:37.4604402Z  args.github_token, args.github_issue_repo, args.github_issue 2024-12-17T23:28:37.4605167Z  ) 2024-12-17T23:28:37.4605595Z  2024-12-17T23:28:37.4606199Z  username = get_potential_pr_author( 2024-12-17T23:28:37.4606849Z  args.github_token, 2024-12-17T23:28:37.4607408Z  args.github_repo, 2024-12-17T23:28:37.4608110Z  args.github_actor, 2024-12-17T23:28:37.4608729Z  args.github_ref_type, 2024-12-17T23:28:37.4609299Z  args.github_branch, 2024-12-17T23:28:37.4609991Z  ) 2024-12-17T23:28:37.4610469Z  2024-12-17T23:28:37.4611030Z  is_canary = args.github_repo == "pytorch/pytorch-canary" 2024-12-17T23:28:37.4611828Z  2024-12-17T23:28:37.4612365Z  runner_label_prefix = get_runner_prefix( 2024-12-17T23:28:37.4612995Z  rollout_state, 2024-12-17T23:28:37.4613701Z  (args.github_issue_owner, username), 2024-12-17T23:28:37.4614366Z  args.github_branch, 2024-12-17T23:28:37.4614969Z  args.eligible_experiments, 2024-12-17T23:28:37.4615671Z  is_canary, 2024-12-17T23:28:37.4616236Z  ) 2024-12-17T23:28:37.4616664Z  2024-12-17T23:28:37.4617217Z  except Exception as e: 2024-12-17T23:28:37.4617975Z  log.error( 2024-12-17T23:28:37.4618865Z  f"Failed to get issue. Defaulting to Meta runners and no experiments. Exception: {e}" 2024-12-17T23:28:37.4619727Z  ) 2024-12-17T23:28:37.4620238Z  2024-12-17T23:28:37.4620918Z  set_github_output(GH_OUTPUT_KEY_LABEL_TYPE, runner_label_prefix) 2024-12-17T23:28:37.4621664Z  2024-12-17T23:28:37.4622127Z  2024-12-17T23:28:37.4622642Z if __name__ == "__main__": 2024-12-17T23:28:37.4623228Z  main() 2024-12-17T23:28:37.4623723Z  2024-12-17T23:28:37.4624221Z EOF 2024-12-17T23:28:37.4624679Z  2024-12-17T23:28:37.4625162Z cat runner_determinator.py 2024-12-17T23:28:37.4950820Z shell: /usr/bin/bash -e {0} 2024-12-17T23:28:37.4951956Z env: 2024-12-17T23:28:37.4952805Z GITHUB_TOKEN: *** 2024-12-17T23:28:37.4953526Z ISSUE_NUMBER: 5132 2024-12-17T23:28:37.4954185Z TRIGGERING_ACTOR: malfet 2024-12-17T23:28:37.4954796Z ISSUE_OWNER: 2024-12-17T23:28:37.4955452Z CHECK_EXPERIMENTS: 2024-12-17T23:28:37.4956087Z PR_NUMBER: 2024-12-17T23:28:37.4956628Z ##[endgroup] 2024-12-17T23:28:37.5187644Z # flake8: noqa: G004 2024-12-17T23:28:37.5188100Z 2024-12-17T23:28:37.5188546Z # Note: Copies of this script in runner_determinator.py and _runner-determinator.yml 2024-12-17T23:28:37.5190049Z # must be kept in sync. You can do it easily by running the following command: 2024-12-17T23:28:37.5190958Z # python .github/scripts/update_runner_determinator.py 2024-12-17T23:28:37.5191506Z 2024-12-17T23:28:37.5191673Z """ 2024-12-17T23:28:37.5192509Z This runner determinator is used to determine which set of runners to run a 2024-12-17T23:28:37.5193517Z GitHub job on. It uses the first comment of a GitHub issue (by default 2024-12-17T23:28:37.5194520Z https://github.com/pytorch/test-infra/issues/5132) to define the configuration 2024-12-17T23:28:37.5195594Z of which runners should be used to run which job. 2024-12-17T23:28:37.5196078Z 2024-12-17T23:28:37.5196515Z The configuration has two parts, the settings and a list of opted-in users, 2024-12-17T23:28:37.5197793Z separated by a line containing "---". If the line is not present, the 2024-12-17T23:28:37.5198816Z settings are considered to be empty with only the second part, the user 2024-12-17T23:28:37.5199695Z list, defined. 2024-12-17T23:28:37.5200005Z 2024-12-17T23:28:37.5200388Z The first part is a YAML block that defines the rollout settings. This can be 2024-12-17T23:28:37.5201423Z used to define any settings that are needed to determine which runners to use. 2024-12-17T23:28:37.5202493Z It's fields are defined by the RolloutSettings class below. 2024-12-17T23:28:37.5203007Z 2024-12-17T23:28:37.5203451Z The second part is a list of users who are explicitly opted in to the LF fleet. 2024-12-17T23:28:37.5204487Z The user list is also a comma separated list of additional features or 2024-12-17T23:28:37.5205412Z experiments which the user could be opted in to. 2024-12-17T23:28:37.5205888Z 2024-12-17T23:28:37.5206214Z The user list has the following rules: 2024-12-17T23:28:37.5206661Z 2024-12-17T23:28:37.5207003Z - Users are GitHub usernames, which must start with the @ prefix 2024-12-17T23:28:37.5207968Z - Each user is also a comma-separated list of features/experiments to enable 2024-12-17T23:28:37.5208915Z - A "#" prefix opts the user out of all experiments 2024-12-17T23:28:37.5209401Z 2024-12-17T23:28:37.5209632Z Example config: 2024-12-17T23:28:37.5210180Z # A list of experiments that can be opted into. 2024-12-17T23:28:37.5211093Z # This defines the behavior they'll induce when opted into. 2024-12-17T23:28:37.5211849Z # Expected syntax is: 2024-12-17T23:28:37.5212602Z # [experiment_name]: # Name of the experiment. Also used for the label prefix. 2024-12-17T23:28:37.5214170Z # rollout_perc: [int] # % of workflows to run with this experiment when users are not opted in. 2024-12-17T23:28:37.5214866Z 2024-12-17T23:28:37.5215312Z experiments: 2024-12-17T23:28:37.5215828Z lf: 2024-12-17T23:28:37.5216434Z rollout_percent: 25 2024-12-17T23:28:37.5217062Z all_branches: false 2024-12-17T23:28:37.5217607Z default: true 2024-12-17T23:28:37.5218225Z --- 2024-12-17T23:28:37.5218505Z 2024-12-17T23:28:37.5218745Z # Opt-ins: 2024-12-17T23:28:37.5219514Z # Users can opt into the LF fleet by adding their GitHub username to this list 2024-12-17T23:28:37.5220799Z # and specifying experiments to enable in a comma-separated list. 2024-12-17T23:28:37.5221806Z # To always opt out of an experiment, prefix it with a "-". 2024-12-17T23:28:37.5222580Z # Experiments should be from the above list. 2024-12-17T23:28:37.5223097Z 2024-12-17T23:28:37.5223292Z @User1,-lf,split_build 2024-12-17T23:28:37.5223991Z @User2,lf 2024-12-17T23:28:37.5224584Z @User3,split_build 2024-12-17T23:28:37.5225127Z """ 2024-12-17T23:28:37.5225469Z 2024-12-17T23:28:37.5225637Z import json 2024-12-17T23:28:37.5226385Z import logging 2024-12-17T23:28:37.5226996Z import os 2024-12-17T23:28:37.5227558Z import random 2024-12-17T23:28:37.5228073Z import re 2024-12-17T23:28:37.5228635Z import sys 2024-12-17T23:28:37.5229609Z from argparse import ArgumentParser 2024-12-17T23:28:37.5230373Z from functools import lru_cache 2024-12-17T23:28:37.5230985Z from logging import LogRecord 2024-12-17T23:28:37.5231895Z from typing import Any, Dict, FrozenSet, Iterable, List, NamedTuple, Set, Tuple 2024-12-17T23:28:37.5232826Z from urllib.request import Request, urlopen 2024-12-17T23:28:37.5233275Z 2024-12-17T23:28:37.5233518Z import yaml 2024-12-17T23:28:37.5234099Z from github import Auth, Github 2024-12-17T23:28:37.5234719Z from github.Issue import Issue 2024-12-17T23:28:37.5235148Z 2024-12-17T23:28:37.5235155Z 2024-12-17T23:28:37.5235395Z DEFAULT_LABEL_PREFIX = "" # use meta runners 2024-12-17T23:28:37.5236214Z WORKFLOW_LABEL_LF = "lf." # use runners from the linux foundation 2024-12-17T23:28:37.5237496Z WORKFLOW_LABEL_LF_CANARY = "lf.c." # use canary runners from the linux foundation 2024-12-17T23:28:37.5238208Z 2024-12-17T23:28:37.5238622Z GITHUB_OUTPUT = os.getenv("GITHUB_OUTPUT", "") 2024-12-17T23:28:37.5239587Z GH_OUTPUT_KEY_AMI = "runner-ami" 2024-12-17T23:28:37.5240215Z GH_OUTPUT_KEY_LABEL_TYPE = "label-type" 2024-12-17T23:28:37.5240975Z OPT_OUT_LABEL = "no-runner-experiments" 2024-12-17T23:28:37.5241462Z 2024-12-17T23:28:37.5241687Z SETTING_EXPERIMENTS = "experiments" 2024-12-17T23:28:37.5242112Z 2024-12-17T23:28:37.5242362Z LF_FLEET_EXPERIMENT = "lf" 2024-12-17T23:28:37.5243246Z CANARY_FLEET_SUFFIX = ".c" 2024-12-17T23:28:37.5243692Z 2024-12-17T23:28:37.5243698Z 2024-12-17T23:28:37.5243934Z class Experiment(NamedTuple): 2024-12-17T23:28:37.5244549Z rollout_perc: float = ( 2024-12-17T23:28:37.5245355Z 0 # Percentage of workflows to experiment on when user is not opted-in. 2024-12-17T23:28:37.5246413Z ) 2024-12-17T23:28:37.5246927Z all_branches: bool = ( 2024-12-17T23:28:37.5247735Z False # If True, the experiment is also enabled on the exception branches 2024-12-17T23:28:37.5248587Z ) 2024-12-17T23:28:37.5249093Z default: bool = ( 2024-12-17T23:28:37.5249834Z True # If True, the experiment is enabled by default for all queries 2024-12-17T23:28:37.5250649Z ) 2024-12-17T23:28:37.5250923Z 2024-12-17T23:28:37.5251169Z # Add more fields as needed 2024-12-17T23:28:37.5251530Z 2024-12-17T23:28:37.5251536Z 2024-12-17T23:28:37.5251815Z class Settings(NamedTuple): 2024-12-17T23:28:37.5252437Z """ 2024-12-17T23:28:37.5253365Z Settings for the experiments that can be opted into. 2024-12-17T23:28:37.5254592Z """ 2024-12-17T23:28:37.5255108Z 2024-12-17T23:28:37.5255469Z experiments: Dict[str, Experiment] = {} 2024-12-17T23:28:37.5255933Z 2024-12-17T23:28:37.5255978Z 2024-12-17T23:28:37.5256216Z class ColorFormatter(logging.Formatter): 2024-12-17T23:28:37.5257074Z """Color codes the log messages based on the log level""" 2024-12-17T23:28:37.5257802Z 2024-12-17T23:28:37.5258011Z COLORS = { 2024-12-17T23:28:37.5258566Z "WARNING": "\033[33m", # Yellow 2024-12-17T23:28:37.5259426Z "ERROR": "\033[31m", # Red 2024-12-17T23:28:37.5260193Z "CRITICAL": "\033[31m", # Red 2024-12-17T23:28:37.5260908Z "INFO": "\033[0m", # Reset 2024-12-17T23:28:37.5261601Z "DEBUG": "\033[0m", # Reset 2024-12-17T23:28:37.5262173Z } 2024-12-17T23:28:37.5262481Z 2024-12-17T23:28:37.5262744Z def format(self, record: LogRecord) -> str: 2024-12-17T23:28:37.5263691Z log_color = self.COLORS.get(record.levelname, "\033[0m") # Default to reset 2024-12-17T23:28:37.5264581Z record.msg = f"{log_color}{record.msg}\033[0m" 2024-12-17T23:28:37.5265315Z return super().format(record) 2024-12-17T23:28:37.5265708Z 2024-12-17T23:28:37.5265715Z 2024-12-17T23:28:37.5266046Z handler = logging.StreamHandler() 2024-12-17T23:28:37.5266863Z handler.setFormatter(ColorFormatter(fmt="%(levelname)-8s: %(message)s")) 2024-12-17T23:28:37.5267554Z 2024-12-17T23:28:37.5267824Z log = logging.getLogger(os.path.basename(__file__)) 2024-12-17T23:28:37.5268603Z log.addHandler(handler) 2024-12-17T23:28:37.5269469Z log.setLevel(logging.INFO) 2024-12-17T23:28:37.5269828Z 2024-12-17T23:28:37.5269837Z 2024-12-17T23:28:37.5270107Z def set_github_output(key: str, value: str) -> None: 2024-12-17T23:28:37.5270886Z """ 2024-12-17T23:28:37.5271544Z Defines outputs of the github action that invokes this script 2024-12-17T23:28:37.5272275Z """ 2024-12-17T23:28:37.5272851Z if not GITHUB_OUTPUT: 2024-12-17T23:28:37.5274072Z # See https://github.blog/changelog/2022-10-11-github-actions-deprecating-save-state-and-set-output-commands/ for deprecation notice 2024-12-17T23:28:37.5275362Z log.warning( 2024-12-17T23:28:37.5276422Z "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:37.5277501Z ) 2024-12-17T23:28:37.5287534Z print(f"::set-output name={key}::{value}") 2024-12-17T23:28:37.5288384Z return 2024-12-17T23:28:37.5288715Z 2024-12-17T23:28:37.5289205Z with open(GITHUB_OUTPUT, "a") as f: 2024-12-17T23:28:37.5289905Z log.info(f"Setting output: {key}='{value}'") 2024-12-17T23:28:37.5290691Z f.write(f"{key}={value}\n") 2024-12-17T23:28:37.5291166Z 2024-12-17T23:28:37.5291174Z 2024-12-17T23:28:37.5291507Z def _str_comma_separated_to_set(value: str) -> FrozenSet[str]: 2024-12-17T23:28:37.5292261Z return frozenset( 2024-12-17T23:28:37.5293058Z filter(lambda itm: itm != "", map(str.strip, value.strip(" \n\t").split(","))) 2024-12-17T23:28:37.5293928Z ) 2024-12-17T23:28:37.5294208Z 2024-12-17T23:28:37.5294215Z 2024-12-17T23:28:37.5294447Z def parse_args() -> Any: 2024-12-17T23:28:37.5295209Z parser = ArgumentParser("Get dynamic rollout settings") 2024-12-17T23:28:37.5296267Z parser.add_argument("--github-token", type=str, required=True, help="GitHub token") 2024-12-17T23:28:37.5297183Z parser.add_argument( 2024-12-17T23:28:37.5297858Z "--github-issue-repo", 2024-12-17T23:28:37.5298484Z type=str, 2024-12-17T23:28:37.5299019Z required=False, 2024-12-17T23:28:37.5299676Z default="pytorch/test-infra", 2024-12-17T23:28:37.5300367Z help="GitHub repo to get the issue", 2024-12-17T23:28:37.5301024Z ) 2024-12-17T23:28:37.5301602Z parser.add_argument( 2024-12-17T23:28:37.5302193Z "--github-repo", 2024-12-17T23:28:37.5302755Z type=str, 2024-12-17T23:28:37.5303370Z required=True, 2024-12-17T23:28:37.5303981Z help="GitHub repo where CI is running", 2024-12-17T23:28:37.5304641Z ) 2024-12-17T23:28:37.5305213Z parser.add_argument( 2024-12-17T23:28:37.5305961Z "--github-issue", type=int, required=True, help="GitHub issue number" 2024-12-17T23:28:37.5306745Z ) 2024-12-17T23:28:37.5307282Z parser.add_argument( 2024-12-17T23:28:37.5308195Z "--github-actor", type=str, required=True, help="GitHub triggering_actor" 2024-12-17T23:28:37.5309437Z ) 2024-12-17T23:28:37.5310049Z parser.add_argument( 2024-12-17T23:28:37.5310844Z "--github-issue-owner", type=str, required=True, help="GitHub issue owner" 2024-12-17T23:28:37.5311672Z ) 2024-12-17T23:28:37.5312236Z parser.add_argument( 2024-12-17T23:28:37.5313048Z "--github-branch", type=str, required=True, help="Current GitHub branch or tag" 2024-12-17T23:28:37.5313875Z ) 2024-12-17T23:28:37.5314419Z parser.add_argument( 2024-12-17T23:28:37.5315021Z "--github-ref-type", 2024-12-17T23:28:37.5315598Z type=str, 2024-12-17T23:28:37.5316170Z required=True, 2024-12-17T23:28:37.5316799Z help="Current GitHub ref type, branch or tag", 2024-12-17T23:28:37.5317470Z ) 2024-12-17T23:28:37.5318023Z parser.add_argument( 2024-12-17T23:28:37.5318622Z "--eligible-experiments", 2024-12-17T23:28:37.5319271Z type=_str_comma_separated_to_set, 2024-12-17T23:28:37.5319978Z required=False, 2024-12-17T23:28:37.5320547Z default="", 2024-12-17T23:28:37.5321503Z help="comma separated list of experiments to check, if omitted all experiments marked with default=True are checked", 2024-12-17T23:28:37.5322606Z ) 2024-12-17T23:28:37.5323125Z parser.add_argument( 2024-12-17T23:28:37.5323682Z "--pr-number", 2024-12-17T23:28:37.5324291Z type=str, 2024-12-17T23:28:37.5324821Z required=False, 2024-12-17T23:28:37.5325358Z default="", 2024-12-17T23:28:37.5326022Z help="the optional PR number where this is run", 2024-12-17T23:28:37.5326706Z ) 2024-12-17T23:28:37.5326987Z 2024-12-17T23:28:37.5327236Z return parser.parse_args() 2024-12-17T23:28:37.5327684Z 2024-12-17T23:28:37.5327691Z 2024-12-17T23:28:37.5327984Z def get_gh_client(github_token: str) -> Github: 2024-12-17T23:28:37.5328720Z auth = Auth.Token(github_token) 2024-12-17T23:28:37.5329348Z return Github(auth=auth) 2024-12-17T23:28:37.5329800Z 2024-12-17T23:28:37.5329808Z 2024-12-17T23:28:37.5330184Z def get_issue(gh: Github, repo: str, issue_num: int) -> Issue: 2024-12-17T23:28:37.5331113Z repo = gh.get_repo(repo) 2024-12-17T23:28:37.5331746Z return repo.get_issue(number=issue_num) 2024-12-17T23:28:37.5332251Z 2024-12-17T23:28:37.5332259Z 2024-12-17T23:28:37.5332526Z def get_potential_pr_author( 2024-12-17T23:28:37.5333259Z github_token: str, repo: str, username: str, ref_type: str, ref_name: str 2024-12-17T23:28:37.5334071Z ) -> str: 2024-12-17T23:28:37.5334803Z # If the trigger was a new tag added by a bot, this is a ciflow case 2024-12-17T23:28:37.5335896Z # Fetch the actual username from the original PR. The PR number is 2024-12-17T23:28:37.5336816Z # embedded in the tag name: ciflow// 2024-12-17T23:28:37.5337385Z 2024-12-17T23:28:37.5337650Z gh = get_gh_client(github_token) 2024-12-17T23:28:37.5338061Z 2024-12-17T23:28:37.5338363Z if username == "pytorch-bot[bot]" and ref_type == "tag": 2024-12-17T23:28:37.5339131Z split_tag = ref_name.split("/") 2024-12-17T23:28:37.5339854Z if ( 2024-12-17T23:28:37.5340357Z len(split_tag) == 3 2024-12-17T23:28:37.5340968Z and split_tag[0] == "ciflow" 2024-12-17T23:28:37.5341708Z and split_tag[2].isnumeric() 2024-12-17T23:28:37.5342316Z ): 2024-12-17T23:28:37.5342821Z pr_number = split_tag[2] 2024-12-17T23:28:37.5343512Z try: 2024-12-17T23:28:37.5344073Z repository = gh.get_repo(repo) 2024-12-17T23:28:37.5344799Z pull = repository.get_pull(number=int(pr_number)) 2024-12-17T23:28:37.5345604Z except Exception as e: 2024-12-17T23:28:37.5346241Z raise Exception( # noqa: TRY002 2024-12-17T23:28:37.5347030Z f"issue with pull request {pr_number} from repo {repository}" 2024-12-17T23:28:37.5347900Z ) from e 2024-12-17T23:28:37.5348449Z return pull.user.login 2024-12-17T23:28:37.5349586Z # In all other cases, return the original input username 2024-12-17T23:28:37.5350456Z return username 2024-12-17T23:28:37.5350787Z 2024-12-17T23:28:37.5350794Z 2024-12-17T23:28:37.5351078Z def is_exception_branch(branch: str) -> bool: 2024-12-17T23:28:37.5351691Z """ 2024-12-17T23:28:37.5352563Z Branches that get opted out of experiments by default, until they're explicitly enabled. 2024-12-17T23:28:37.5353478Z """ 2024-12-17T23:28:37.5354357Z return branch.split("/")[0] in {"main", "nightly", "release", "landchecks"} 2024-12-17T23:28:37.5355110Z 2024-12-17T23:28:37.5355116Z 2024-12-17T23:28:37.5355348Z def load_yaml(yaml_text: str) -> Any: 2024-12-17T23:28:37.5355984Z try: 2024-12-17T23:28:37.5356481Z data = yaml.safe_load(yaml_text) 2024-12-17T23:28:37.5357213Z return data 2024-12-17T23:28:37.5357785Z except yaml.YAMLError: 2024-12-17T23:28:37.5358349Z log.exception("Error loading YAML") 2024-12-17T23:28:37.5359093Z raise 2024-12-17T23:28:37.5359393Z 2024-12-17T23:28:37.5359400Z 2024-12-17T23:28:37.5359883Z def extract_settings_user_opt_in_from_text(rollout_state: str) -> Tuple[str, str]: 2024-12-17T23:28:37.5360805Z """ 2024-12-17T23:28:37.5361557Z Extracts the text with settings, if any, and the opted in users from the rollout state. 2024-12-17T23:28:37.5362278Z 2024-12-17T23:28:37.5362646Z If the issue body contains "---" then the text above that is the settings 2024-12-17T23:28:37.5363569Z and the text below is the list of opted in users. 2024-12-17T23:28:37.5364058Z 2024-12-17T23:28:37.5364455Z If it doesn't contain "---" then the settings are empty and the rest is the users. 2024-12-17T23:28:37.5365312Z """ 2024-12-17T23:28:37.5365924Z rollout_state_parts = rollout_state.split("---") 2024-12-17T23:28:37.5366650Z if len(rollout_state_parts) >= 2: 2024-12-17T23:28:37.5367408Z return rollout_state_parts[0], rollout_state_parts[1] 2024-12-17T23:28:37.5368184Z else: 2024-12-17T23:28:37.5368700Z return "", rollout_state 2024-12-17T23:28:37.5369541Z 2024-12-17T23:28:37.5369557Z 2024-12-17T23:28:37.5369946Z class UserOptins(Dict[str, List[str]]): 2024-12-17T23:28:37.5371109Z """ 2024-12-17T23:28:37.5371795Z Dictionary of users with a list of features they have opted into 2024-12-17T23:28:37.5372590Z """ 2024-12-17T23:28:37.5372872Z 2024-12-17T23:28:37.5372879Z 2024-12-17T23:28:37.5373329Z def parse_user_opt_in_from_text(user_optin_text: str) -> UserOptins: 2024-12-17T23:28:37.5374155Z """ 2024-12-17T23:28:37.5374967Z 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:37.5375750Z 2024-12-17T23:28:37.5376453Z Users are GitHub usernames with the @ prefix. Each user is also a comma-separated list of features/experiments to enable. 2024-12-17T23:28:37.5377606Z - Example line: "@User1,lf,split_build" 2024-12-17T23:28:37.5378454Z - A "#" prefix indicates the user is opted out of all experiments 2024-12-17T23:28:37.5379040Z 2024-12-17T23:28:37.5379048Z 2024-12-17T23:28:37.5379322Z """ 2024-12-17T23:28:37.5379854Z optins = UserOptins() 2024-12-17T23:28:37.5380434Z for user in user_optin_text.split("\n"): 2024-12-17T23:28:37.5381186Z user = user.strip("\r\n\t -") 2024-12-17T23:28:37.5381890Z if not user or not user.startswith("@"): 2024-12-17T23:28:37.5382537Z # Not a valid user. Skip 2024-12-17T23:28:37.5383229Z continue 2024-12-17T23:28:37.5383605Z 2024-12-17T23:28:37.5383794Z if user: 2024-12-17T23:28:37.5384328Z usr_name = user.split(",")[0].strip("@") 2024-12-17T23:28:37.5385217Z optins[usr_name] = [exp.strip(" ") for exp in user.split(",")[1:]] 2024-12-17T23:28:37.5385836Z 2024-12-17T23:28:37.5386027Z return optins 2024-12-17T23:28:37.5386340Z 2024-12-17T23:28:37.5386346Z 2024-12-17T23:28:37.5386705Z def is_valid_experiment_name(experiment_name: str) -> bool: 2024-12-17T23:28:37.5387591Z """ 2024-12-17T23:28:37.5388170Z Check if the experiment name is valid. 2024-12-17T23:28:37.5389110Z A valid name: 2024-12-17T23:28:37.5389973Z - Contains only alphanumeric characters and the special characters "_" & "-" 2024-12-17T23:28:37.5391058Z - The special characters "_" & "-" shouldn't be the first or last characters 2024-12-17T23:28:37.5391925Z - Cannot contain spaces 2024-12-17T23:28:37.5392526Z """ 2024-12-17T23:28:37.5392866Z 2024-12-17T23:28:37.5393170Z valid_char_regex = r"^[a-zA-Z0-9]([\w-]*[a-zA-Z0-9])?$" 2024-12-17T23:28:37.5394023Z valid = bool(re.match(valid_char_regex, experiment_name)) 2024-12-17T23:28:37.5394534Z 2024-12-17T23:28:37.5394787Z if valid: 2024-12-17T23:28:37.5395351Z return True 2024-12-17T23:28:37.5395667Z 2024-12-17T23:28:37.5395895Z log.error( 2024-12-17T23:28:37.5397615Z 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:37.5399426Z ) 2024-12-17T23:28:37.5399940Z return False 2024-12-17T23:28:37.5400353Z 2024-12-17T23:28:37.5400360Z 2024-12-17T23:28:37.5400713Z def parse_settings_from_text(settings_text: str) -> Settings: 2024-12-17T23:28:37.5401499Z """ 2024-12-17T23:28:37.5402193Z Parse the experiments from the issue body into a list of ExperimentSettings 2024-12-17T23:28:37.5403142Z """ 2024-12-17T23:28:37.5403638Z try: 2024-12-17T23:28:37.5404116Z if settings_text: 2024-12-17T23:28:37.5405062Z # Escape the backtick as well so that we can have the settings in a code block on the GH issue 2024-12-17T23:28:37.5406013Z # for easy reading 2024-12-17T23:28:37.5406921Z # Note: Using ascii for the backtick so that the cat step in _runner-determinator.yml doesn't choke on 2024-12-17T23:28:37.5408056Z # the backtick character in shell commands. 2024-12-17T23:28:37.5408809Z backtick = chr(96) # backtick character 2024-12-17T23:28:37.5409593Z settings_text = settings_text.strip(f"\r\n\t{backtick} ") 2024-12-17T23:28:37.5410702Z settings = load_yaml(settings_text) 2024-12-17T23:28:37.5411155Z 2024-12-17T23:28:37.5411628Z # For now we just load experiments. We can expand this if/when we add more settings 2024-12-17T23:28:37.5412514Z experiments = {} 2024-12-17T23:28:37.5412979Z 2024-12-17T23:28:37.5413387Z for exp_name, exp_settings in settings.get(SETTING_EXPERIMENTS).items(): 2024-12-17T23:28:37.5414299Z if not is_valid_experiment_name(exp_name): 2024-12-17T23:28:37.5415576Z # 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:37.5416839Z continue 2024-12-17T23:28:37.5417251Z 2024-12-17T23:28:37.5417467Z valid_settings = {} 2024-12-17T23:28:37.5418127Z for setting in exp_settings: 2024-12-17T23:28:37.5418900Z if setting not in Experiment._fields: 2024-12-17T23:28:37.5419618Z log.warning( 2024-12-17T23:28:37.5420463Z f"Unexpected setting in experiment: {setting} = {exp_settings[setting]}" 2024-12-17T23:28:37.5421375Z ) 2024-12-17T23:28:37.5421958Z else: 2024-12-17T23:28:37.5422597Z valid_settings[setting] = exp_settings[setting] 2024-12-17T23:28:37.5423163Z 2024-12-17T23:28:37.5423518Z experiments[exp_name] = Experiment(**valid_settings) 2024-12-17T23:28:37.5424279Z return Settings(experiments) 2024-12-17T23:28:37.5424745Z 2024-12-17T23:28:37.5424937Z except Exception: 2024-12-17T23:28:37.5425627Z log.exception("Failed to parse settings") 2024-12-17T23:28:37.5426114Z 2024-12-17T23:28:37.5426463Z return Settings() 2024-12-17T23:28:37.5426849Z 2024-12-17T23:28:37.5426856Z 2024-12-17T23:28:37.5427117Z def parse_settings(rollout_state: str) -> Settings: 2024-12-17T23:28:37.5427949Z """ 2024-12-17T23:28:37.5428510Z Parse settings, if any, from the rollout state. 2024-12-17T23:28:37.5429647Z 2024-12-17T23:28:37.5430031Z If the issue body contains "---" then the text above that is the settings 2024-12-17T23:28:37.5431070Z and the text below is the list of opted in users. 2024-12-17T23:28:37.5431563Z 2024-12-17T23:28:37.5432041Z If it doesn't contain "---" then the settings are empty and the default values are used. 2024-12-17T23:28:37.5432891Z """ 2024-12-17T23:28:37.5433721Z settings_text, _ = extract_settings_user_opt_in_from_text(rollout_state) 2024-12-17T23:28:37.5434638Z return parse_settings_from_text(settings_text) 2024-12-17T23:28:37.5435126Z 2024-12-17T23:28:37.5435133Z 2024-12-17T23:28:37.5435400Z def parse_users(rollout_state: str) -> UserOptins: 2024-12-17T23:28:37.5436261Z """ 2024-12-17T23:28:37.5436839Z Parse users from the rollout state. 2024-12-17T23:28:37.5437283Z 2024-12-17T23:28:37.5437466Z """ 2024-12-17T23:28:37.5438266Z _, users_text = extract_settings_user_opt_in_from_text(rollout_state) 2024-12-17T23:28:37.5439150Z return parse_user_opt_in_from_text(users_text) 2024-12-17T23:28:37.5439626Z 2024-12-17T23:28:37.5439632Z 2024-12-17T23:28:37.5440058Z def is_user_opted_in(user: str, user_optins: UserOptins, experiment_name: str) -> bool: 2024-12-17T23:28:37.5441050Z """ 2024-12-17T23:28:37.5441599Z Check if a user is opted into an experiment 2024-12-17T23:28:37.5442353Z """ 2024-12-17T23:28:37.5442937Z return experiment_name in user_optins.get(user, []) 2024-12-17T23:28:37.5443475Z 2024-12-17T23:28:37.5443482Z 2024-12-17T23:28:37.5443937Z def is_user_opted_out(user: str, user_optins: UserOptins, experiment_name: str) -> bool: 2024-12-17T23:28:37.5444901Z """ 2024-12-17T23:28:37.5445492Z Check if a user explicitly opted out of an experiment 2024-12-17T23:28:37.5446214Z """ 2024-12-17T23:28:37.5446924Z # if the experiment is prefixed with a "-", then it's an opt-out 2024-12-17T23:28:37.5447937Z experiment_optout = "-" + experiment_name 2024-12-17T23:28:37.5448739Z if experiment_optout not in user_optins.get(user, []): 2024-12-17T23:28:37.5449532Z return False 2024-12-17T23:28:37.5449883Z 2024-12-17T23:28:37.5450184Z if is_user_opted_in(user, user_optins, experiment_name): 2024-12-17T23:28:37.5450945Z log.warning( 2024-12-17T23:28:37.5451948Z f"User {user} is opted into experiment {experiment_name}, but also opted out of it. Defaulting to opting out" 2024-12-17T23:28:37.5452964Z ) 2024-12-17T23:28:37.5453297Z 2024-12-17T23:28:37.5453491Z return True 2024-12-17T23:28:37.5453801Z 2024-12-17T23:28:37.5453807Z 2024-12-17T23:28:37.5454092Z def get_runner_prefix( 2024-12-17T23:28:37.5454696Z rollout_state: str, 2024-12-17T23:28:37.5455272Z workflow_requestors: Iterable[str], 2024-12-17T23:28:37.5455971Z branch: str, 2024-12-17T23:28:37.5456634Z eligible_experiments: FrozenSet[str] = frozenset(), 2024-12-17T23:28:37.5457348Z is_canary: bool = False, 2024-12-17T23:28:37.5458003Z ) -> str: 2024-12-17T23:28:37.5458556Z settings = parse_settings(rollout_state) 2024-12-17T23:28:37.5459277Z user_optins = parse_users(rollout_state) 2024-12-17T23:28:37.5459749Z 2024-12-17T23:28:37.5460019Z fleet_prefix = "" 2024-12-17T23:28:37.5460610Z prefixes = [] 2024-12-17T23:28:37.5461344Z for experiment_name, experiment_settings in settings.experiments.items(): 2024-12-17T23:28:37.5462479Z if not experiment_settings.all_branches and is_exception_branch(branch): 2024-12-17T23:28:37.5463370Z log.info( 2024-12-17T23:28:37.5464158Z f"Branch {branch} is an exception branch. Not enabling experiment {experiment_name}." 2024-12-17T23:28:37.5465120Z ) 2024-12-17T23:28:37.5465814Z continue 2024-12-17T23:28:37.5466159Z 2024-12-17T23:28:37.5466377Z if eligible_experiments: 2024-12-17T23:28:37.5467154Z if experiment_name not in eligible_experiments: 2024-12-17T23:28:37.5467952Z exp_list = ", ".join(eligible_experiments) 2024-12-17T23:28:37.5468621Z log.info( 2024-12-17T23:28:37.5469916Z f"Skipping experiment '{experiment_name}', as it is not in the eligible_experiments list: {exp_list}" 2024-12-17T23:28:37.5470942Z ) 2024-12-17T23:28:37.5471443Z continue 2024-12-17T23:28:37.5472115Z elif not experiment_settings.default: 2024-12-17T23:28:37.5472801Z log.info( 2024-12-17T23:28:37.5473664Z f"Skipping experiment '{experiment_name}', as it is not a default experiment" 2024-12-17T23:28:37.5474640Z ) 2024-12-17T23:28:37.5475171Z continue 2024-12-17T23:28:37.5475496Z 2024-12-17T23:28:37.5475892Z # Is any workflow_requestor opted out to this experiment? 2024-12-17T23:28:37.5476643Z opted_out_users = [ 2024-12-17T23:28:37.5477242Z requestor 2024-12-17T23:28:37.5477891Z for requestor in workflow_requestors 2024-12-17T23:28:37.5478694Z if is_user_opted_out(requestor, user_optins, experiment_name) 2024-12-17T23:28:37.5479498Z ] 2024-12-17T23:28:37.5479784Z 2024-12-17T23:28:37.5480073Z if opted_out_users: 2024-12-17T23:28:37.5480646Z log.info( 2024-12-17T23:28:37.5481423Z f"{', '.join(opted_out_users)} have opted out of experiment {experiment_name}." 2024-12-17T23:28:37.5482320Z ) 2024-12-17T23:28:37.5482819Z continue 2024-12-17T23:28:37.5483188Z 2024-12-17T23:28:37.5483488Z # Is any workflow_requestor opted in to this experiment? 2024-12-17T23:28:37.5484300Z opted_in_users = [ 2024-12-17T23:28:37.5484914Z requestor 2024-12-17T23:28:37.5485509Z for requestor in workflow_requestors 2024-12-17T23:28:37.5486369Z if is_user_opted_in(requestor, user_optins, experiment_name) 2024-12-17T23:28:37.5487135Z ] 2024-12-17T23:28:37.5487636Z 2024-12-17T23:28:37.5487839Z enabled = False 2024-12-17T23:28:37.5488474Z if opted_in_users: 2024-12-17T23:28:37.5489063Z log.info( 2024-12-17T23:28:37.5489812Z f"{', '.join(opted_in_users)} have opted into experiment {experiment_name}." 2024-12-17T23:28:37.5490712Z ) 2024-12-17T23:28:37.5491226Z enabled = True 2024-12-17T23:28:37.5491627Z 2024-12-17T23:28:37.5491871Z elif experiment_settings.rollout_perc: 2024-12-17T23:28:37.5492919Z # If no user is opted in, then we randomly enable the experiment based on the rollout percentage 2024-12-17T23:28:37.5494004Z if random.uniform(0, 100) <= experiment_settings.rollout_perc: 2024-12-17T23:28:37.5494805Z log.info( 2024-12-17T23:28:37.5495901Z f"Based on rollout percentage of {experiment_settings.rollout_perc}%, enabling experiment {experiment_name}." 2024-12-17T23:28:37.5497011Z ) 2024-12-17T23:28:37.5497523Z enabled = True 2024-12-17T23:28:37.5497939Z 2024-12-17T23:28:37.5498195Z if enabled: 2024-12-17T23:28:37.5498813Z label = experiment_name 2024-12-17T23:28:37.5499479Z if experiment_name == LF_FLEET_EXPERIMENT: 2024-12-17T23:28:37.5500518Z # We give some special treatment to the "lf" experiment since determines the fleet we use 2024-12-17T23:28:37.5501558Z # - If it's enabled, then we always list it's prefix first 2024-12-17T23:28:37.5502433Z # - If we're in the canary branch, then we append ".c" to the lf prefix 2024-12-17T23:28:37.5503294Z if is_canary: 2024-12-17T23:28:37.5503941Z label += CANARY_FLEET_SUFFIX 2024-12-17T23:28:37.5504604Z fleet_prefix = label 2024-12-17T23:28:37.5505716Z else: 2024-12-17T23:28:37.5506357Z prefixes.append(label) 2024-12-17T23:28:37.5506785Z 2024-12-17T23:28:37.5506990Z if len(prefixes) > 1: 2024-12-17T23:28:37.5507636Z log.error( 2024-12-17T23:28:37.5509137Z 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:37.5510444Z ) 2024-12-17T23:28:37.5510995Z prefixes = prefixes[:1] 2024-12-17T23:28:37.5511449Z 2024-12-17T23:28:37.5511664Z # Fleet always comes first 2024-12-17T23:28:37.5512269Z if fleet_prefix: 2024-12-17T23:28:37.5512868Z prefixes.insert(0, fleet_prefix) 2024-12-17T23:28:37.5513377Z 2024-12-17T23:28:37.5513651Z return ".".join(prefixes) + "." if prefixes else "" 2024-12-17T23:28:37.5514140Z 2024-12-17T23:28:37.5514147Z 2024-12-17T23:28:37.5514662Z def get_rollout_state_from_issue(github_token: str, repo: str, issue_num: int) -> str: 2024-12-17T23:28:37.5515601Z """ 2024-12-17T23:28:37.5516369Z Gets the first comment of the issue, which contains the desired rollout state. 2024-12-17T23:28:37.5517029Z 2024-12-17T23:28:37.5517479Z The default issue we use - https://github.com/pytorch/test-infra/issues/5132 2024-12-17T23:28:37.5518345Z """ 2024-12-17T23:28:37.5518922Z gh = get_gh_client(github_token) 2024-12-17T23:28:37.5519598Z issue = get_issue(gh, repo, issue_num) 2024-12-17T23:28:37.5520399Z return str(issue.get_comments()[0].body.strip("\n\t ")) 2024-12-17T23:28:37.5520976Z 2024-12-17T23:28:37.5520983Z 2024-12-17T23:28:37.5521414Z def download_json(url: str, headers: Dict[str, str], num_retries: int = 3) -> Any: 2024-12-17T23:28:37.5522315Z for _ in range(num_retries): 2024-12-17T23:28:37.5523015Z try: 2024-12-17T23:28:37.5523557Z req = Request(url=url, headers=headers) 2024-12-17T23:28:37.5524362Z content = urlopen(req, timeout=5).read().decode("utf-8") 2024-12-17T23:28:37.5525229Z return json.loads(content) 2024-12-17T23:28:37.5525874Z except Exception as e: 2024-12-17T23:28:37.5526567Z log.warning(f"Could not download {url}: {e}") 2024-12-17T23:28:37.5527214Z 2024-12-17T23:28:37.5527760Z log.warning(f"All {num_retries} retries exhausted, downloading {url} failed") 2024-12-17T23:28:37.5528585Z return {} 2024-12-17T23:28:37.5528936Z 2024-12-17T23:28:37.5528943Z 2024-12-17T23:28:37.5529150Z @lru_cache(maxsize=None) 2024-12-17T23:28:37.5530045Z def get_pr_info(github_repo: str, github_token: str, pr_number: int) -> Dict[str, Any]: 2024-12-17T23:28:37.5530908Z """ 2024-12-17T23:28:37.5531454Z Dynamically get PR information 2024-12-17T23:28:37.5532147Z """ 2024-12-17T23:28:37.5532743Z github_api = f"https://api.github.com/repos/{github_repo}" 2024-12-17T23:28:37.5533520Z headers = { 2024-12-17T23:28:37.5534196Z "Accept": "application/vnd.github.v3+json", 2024-12-17T23:28:37.5534953Z "Authorization": f"token {github_token}", 2024-12-17T23:28:37.5535651Z } 2024-12-17T23:28:37.5536334Z json_response: Dict[str, Any] = download_json( 2024-12-17T23:28:37.5537098Z url=f"{github_api}/issues/{pr_number}", 2024-12-17T23:28:37.5537806Z headers=headers, 2024-12-17T23:28:37.5538456Z ) 2024-12-17T23:28:37.5538759Z 2024-12-17T23:28:37.5539010Z if not json_response: 2024-12-17T23:28:37.5539701Z log.warning(f"Failed to get the labels for #{pr_number}") 2024-12-17T23:28:37.5540563Z return {} 2024-12-17T23:28:37.5540898Z 2024-12-17T23:28:37.5541147Z return json_response 2024-12-17T23:28:37.5541513Z 2024-12-17T23:28:37.5541519Z 2024-12-17T23:28:37.5541974Z def get_labels(github_repo: str, github_token: str, pr_number: int) -> Set[str]: 2024-12-17T23:28:37.5542958Z """ 2024-12-17T23:28:37.5543648Z Dynamically get the latest list of labels from the pull request 2024-12-17T23:28:37.5544447Z """ 2024-12-17T23:28:37.5545331Z pr_info = get_pr_info(github_repo, github_token, pr_number) 2024-12-17T23:28:37.5546137Z return { 2024-12-17T23:28:37.5546834Z label.get("name") for label in pr_info.get("labels", []) if label.get("name") 2024-12-17T23:28:37.5547810Z } 2024-12-17T23:28:37.5548090Z 2024-12-17T23:28:37.5548096Z 2024-12-17T23:28:37.5548341Z def main() -> None: 2024-12-17T23:28:37.5549121Z args = parse_args() 2024-12-17T23:28:37.5549607Z 2024-12-17T23:28:37.5549888Z runner_label_prefix = DEFAULT_LABEL_PREFIX 2024-12-17T23:28:37.5550402Z 2024-12-17T23:28:37.5550622Z # Check if the PR is opt-out 2024-12-17T23:28:37.5551244Z if args.pr_number: 2024-12-17T23:28:37.5552128Z labels = get_labels(args.github_repo, args.github_token, int(args.pr_number)) 2024-12-17T23:28:37.5553055Z if OPT_OUT_LABEL in labels: 2024-12-17T23:28:37.5553707Z log.info( 2024-12-17T23:28:37.5554626Z f"Opt-out runner determinator because #{args.pr_number} has {OPT_OUT_LABEL} label" 2024-12-17T23:28:37.5555583Z ) 2024-12-17T23:28:37.5556289Z set_github_output(GH_OUTPUT_KEY_LABEL_TYPE, runner_label_prefix) 2024-12-17T23:28:37.5557191Z sys.exit() 2024-12-17T23:28:37.5557570Z 2024-12-17T23:28:37.5557767Z try: 2024-12-17T23:28:37.5558356Z rollout_state = get_rollout_state_from_issue( 2024-12-17T23:28:37.5559279Z args.github_token, args.github_issue_repo, args.github_issue 2024-12-17T23:28:37.5560112Z ) 2024-12-17T23:28:37.5560390Z 2024-12-17T23:28:37.5560645Z username = get_potential_pr_author( 2024-12-17T23:28:37.5561379Z args.github_token, 2024-12-17T23:28:37.5562023Z args.github_repo, 2024-12-17T23:28:37.5562638Z args.github_actor, 2024-12-17T23:28:37.5563305Z args.github_ref_type, 2024-12-17T23:28:37.5563973Z args.github_branch, 2024-12-17T23:28:37.5564573Z ) 2024-12-17T23:28:37.5564925Z 2024-12-17T23:28:37.5565273Z is_canary = args.github_repo == "pytorch/pytorch-canary" 2024-12-17T23:28:37.5565878Z 2024-12-17T23:28:37.5566130Z runner_label_prefix = get_runner_prefix( 2024-12-17T23:28:37.5566823Z rollout_state, 2024-12-17T23:28:37.5567986Z (args.github_issue_owner, username), 2024-12-17T23:28:37.5568710Z args.github_branch, 2024-12-17T23:28:37.5569350Z args.eligible_experiments, 2024-12-17T23:28:37.5570096Z is_canary, 2024-12-17T23:28:37.5570684Z ) 2024-12-17T23:28:37.5570966Z 2024-12-17T23:28:37.5571207Z except Exception as e: 2024-12-17T23:28:37.5571873Z log.error( 2024-12-17T23:28:37.5572710Z f"Failed to get issue. Defaulting to Meta runners and no experiments. Exception: {e}" 2024-12-17T23:28:37.5573642Z ) 2024-12-17T23:28:37.5574009Z 2024-12-17T23:28:37.5574434Z set_github_output(GH_OUTPUT_KEY_LABEL_TYPE, runner_label_prefix) 2024-12-17T23:28:37.5575030Z 2024-12-17T23:28:37.5575038Z 2024-12-17T23:28:37.5575251Z if __name__ == "__main__": 2024-12-17T23:28:37.5575835Z main() 2024-12-17T23:28:37.5576208Z 2024-12-17T23:28:37.5669621Z ##[group]Run python3 -m pip install urllib3==1.26.18 PyGithub==2.3.0 2024-12-17T23:28:37.5670806Z python3 -m pip install urllib3==1.26.18 PyGithub==2.3.0 2024-12-17T23:28:37.5730009Z shell: /usr/bin/bash -e {0} 2024-12-17T23:28:37.5730714Z env: 2024-12-17T23:28:37.5731618Z GITHUB_TOKEN: *** 2024-12-17T23:28:37.5732195Z ISSUE_NUMBER: 5132 2024-12-17T23:28:37.5732825Z TRIGGERING_ACTOR: malfet 2024-12-17T23:28:37.5733538Z ISSUE_OWNER: 2024-12-17T23:28:37.5734082Z CHECK_EXPERIMENTS: 2024-12-17T23:28:37.5734698Z PR_NUMBER: 2024-12-17T23:28:37.5735323Z ##[endgroup] 2024-12-17T23:28:38.9452376Z Defaulting to user installation because normal site-packages is not writeable 2024-12-17T23:28:40.0886477Z Collecting urllib3==1.26.18 2024-12-17T23:28:40.1513619Z Downloading urllib3-1.26.18-py2.py3-none-any.whl (143 kB) 2024-12-17T23:28:40.1843541Z ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 143.8/143.8 KB 6.1 MB/s eta 0:00:00 2024-12-17T23:28:40.2094054Z Collecting PyGithub==2.3.0 2024-12-17T23:28:40.2191954Z Downloading PyGithub-2.3.0-py3-none-any.whl (354 kB) 2024-12-17T23:28:40.2511405Z ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 354.4/354.4 KB 11.5 MB/s eta 0:00:00 2024-12-17T23:28:40.3021085Z Collecting typing-extensions>=4.0.0 2024-12-17T23:28:40.3110671Z Downloading typing_extensions-4.12.2-py3-none-any.whl (37 kB) 2024-12-17T23:28:40.3384435Z Collecting pyjwt[crypto]>=2.4.0 2024-12-17T23:28:40.3472735Z Downloading PyJWT-2.10.1-py3-none-any.whl (22 kB) 2024-12-17T23:28:40.3812989Z Collecting pynacl>=1.4.0 2024-12-17T23:28:40.3903323Z 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.4497726Z ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 856.7/856.7 KB 14.8 MB/s eta 0:00:00 2024-12-17T23:28:40.4750752Z Collecting Deprecated 2024-12-17T23:28:40.4838061Z Downloading Deprecated-1.2.15-py2.py3-none-any.whl (9.9 kB) 2024-12-17T23:28:40.4874772Z 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.5012023Z 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.7229434Z Collecting cffi>=1.4.1 2024-12-17T23:28:40.7322218Z Downloading cffi-1.17.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (446 kB) 2024-12-17T23:28:40.7578836Z ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 446.2/446.2 KB 18.5 MB/s eta 0:00:00 2024-12-17T23:28:40.9541818Z Collecting wrapt<2,>=1.10 2024-12-17T23:28:40.9648796Z 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.9698895Z ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 82.7/82.7 KB 21.7 MB/s eta 0:00:00 2024-12-17T23:28:40.9856262Z Collecting pycparser 2024-12-17T23:28:40.9944708Z Downloading pycparser-2.22-py3-none-any.whl (117 kB) 2024-12-17T23:28:41.0002099Z ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 117.6/117.6 KB 29.0 MB/s eta 0:00:00 2024-12-17T23:28:41.3138227Z Installing collected packages: wrapt, urllib3, typing-extensions, pyjwt, pycparser, Deprecated, cffi, pynacl, PyGithub 2024-12-17T23:28:41.7732851Z 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.8465417Z ##[group]Run curr_branch="release/2.6" 2024-12-17T23:28:41.8465936Z curr_branch="release/2.6" 2024-12-17T23:28:41.8466873Z curr_ref_type="branch" 2024-12-17T23:28:41.8467247Z echo "Current branch is '$curr_branch'" 2024-12-17T23:28:41.8467596Z  2024-12-17T23:28:41.8467967Z python3 runner_determinator.py \ 2024-12-17T23:28:41.8468360Z  --github-token "$GITHUB_TOKEN" \ 2024-12-17T23:28:41.8468912Z  --github-issue "$ISSUE_NUMBER" \ 2024-12-17T23:28:41.8469387Z  --github-branch "$curr_branch" \ 2024-12-17T23:28:41.8469790Z  --github-actor "$TRIGGERING_ACTOR" \ 2024-12-17T23:28:41.8470171Z  --github-issue-owner "$ISSUE_OWNER" \ 2024-12-17T23:28:41.8470671Z  --github-ref-type "$curr_ref_type" \ 2024-12-17T23:28:41.8471070Z  --github-repo "$GITHUB_REPOSITORY" \ 2024-12-17T23:28:41.8471465Z  --eligible-experiments "$CHECK_EXPERIMENTS" \ 2024-12-17T23:28:41.8472028Z  --pr-number "${PR_NUMBER}" 2024-12-17T23:28:41.8529756Z shell: /usr/bin/bash -e {0} 2024-12-17T23:28:41.8530153Z env: 2024-12-17T23:28:41.8530870Z GITHUB_TOKEN: *** 2024-12-17T23:28:41.8531307Z ISSUE_NUMBER: 5132 2024-12-17T23:28:41.8531652Z TRIGGERING_ACTOR: malfet 2024-12-17T23:28:41.8531982Z ISSUE_OWNER: 2024-12-17T23:28:41.8532364Z CHECK_EXPERIMENTS: 2024-12-17T23:28:41.8532694Z PR_NUMBER: 2024-12-17T23:28:41.8532975Z ##[endgroup] 2024-12-17T23:28:41.8609972Z Current branch is 'release/2.6' 2024-12-17T23:28:43.3715267Z INFO : Based on rollout percentage of 95%, enabling experiment lf. 2024-12-17T23:28:43.3716454Z INFO : Skipping experiment 'awsa100', as it is not a default experiment 2024-12-17T23:28:43.3717354Z INFO : Setting output: label-type='lf.' 2024-12-17T23:28:43.4003278Z Evaluate and set job outputs 2024-12-17T23:28:43.4009973Z Set output 'label-type' 2024-12-17T23:28:43.4012062Z Cleaning up orphan processes