2024-12-17T23:33:49.9532929Z Current runner version: '2.321.0' 2024-12-17T23:33:49.9562121Z ##[group]Operating System 2024-12-17T23:33:49.9562920Z Ubuntu 2024-12-17T23:33:49.9563402Z 22.04.5 2024-12-17T23:33:49.9564015Z LTS 2024-12-17T23:33:49.9564461Z ##[endgroup] 2024-12-17T23:33:49.9564978Z ##[group]Runner Image 2024-12-17T23:33:49.9565651Z Image: ubuntu-22.04 2024-12-17T23:33:49.9566132Z Version: 20241215.1.0 2024-12-17T23:33:49.9567126Z Included Software: https://github.com/actions/runner-images/blob/ubuntu22/20241215.1/images/ubuntu/Ubuntu2204-Readme.md 2024-12-17T23:33:49.9568969Z Image Release: https://github.com/actions/runner-images/releases/tag/ubuntu22%2F20241215.1 2024-12-17T23:33:49.9569923Z ##[endgroup] 2024-12-17T23:33:49.9570387Z ##[group]Runner Image Provisioner 2024-12-17T23:33:49.9571107Z 2.0.404.1 2024-12-17T23:33:49.9571575Z ##[endgroup] 2024-12-17T23:33:49.9572656Z ##[group]GITHUB_TOKEN Permissions 2024-12-17T23:33:49.9574739Z Contents: read 2024-12-17T23:33:49.9575259Z Metadata: read 2024-12-17T23:33:49.9576063Z ##[endgroup] 2024-12-17T23:33:49.9578996Z Secret source: Actions 2024-12-17T23:33:49.9580199Z Prepare workflow directory 2024-12-17T23:33:50.0053888Z Prepare all required actions 2024-12-17T23:33:50.0107064Z Uses: pytorch/pytorch/.github/workflows/_runner-determinator.yml@refs/heads/release/2.6 (0cdf8b1d09254cfda66191d1bd01e3041c3c76f7) 2024-12-17T23:33:50.0112321Z ##[group] Inputs 2024-12-17T23:33:50.0113047Z check_experiments: 2024-12-17T23:33:50.0113664Z triggering_actor: malfet 2024-12-17T23:33:50.0114197Z issue_owner: 2024-12-17T23:33:50.0114784Z curr_branch: release/2.6 2024-12-17T23:33:50.0115392Z curr_ref_type: branch 2024-12-17T23:33:50.0115901Z issue_number: 5132 2024-12-17T23:33:50.0116486Z ##[endgroup] 2024-12-17T23:33:50.0117201Z Complete job name: before-test / get-label-type / runner-determinator 2024-12-17T23:33:50.5995648Z ##[group]Run cat < runner_determinator.py 2024-12-17T23:33:50.5998063Z cat < runner_determinator.py 2024-12-17T23:33:50.5998862Z # flake8: noqa: G004 2024-12-17T23:33:50.5999489Z  2024-12-17T23:33:50.6000317Z # Note: Copies of this script in runner_determinator.py and _runner-determinator.yml 2024-12-17T23:33:50.6001548Z # must be kept in sync. You can do it easily by running the following command: 2024-12-17T23:33:50.6002536Z # python .github/scripts/update_runner_determinator.py 2024-12-17T23:33:50.6003301Z  2024-12-17T23:33:50.6003848Z """ 2024-12-17T23:33:50.6004630Z This runner determinator is used to determine which set of runners to run a 2024-12-17T23:33:50.6005673Z GitHub job on. It uses the first comment of a GitHub issue (by default 2024-12-17T23:33:50.6006969Z https://github.com/pytorch/test-infra/issues/5132) to define the configuration 2024-12-17T23:33:50.6008222Z of which runners should be used to run which job. 2024-12-17T23:33:50.6008976Z  2024-12-17T23:33:50.6009827Z The configuration has two parts, the settings and a list of opted-in users, 2024-12-17T23:33:50.6010951Z separated by a line containing "---". If the line is not present, the 2024-12-17T23:33:50.6011983Z settings are considered to be empty with only the second part, the user 2024-12-17T23:33:50.6012946Z list, defined. 2024-12-17T23:33:50.6013517Z  2024-12-17T23:33:50.6014203Z The first part is a YAML block that defines the rollout settings. This can be 2024-12-17T23:33:50.6015421Z used to define any settings that are needed to determine which runners to use. 2024-12-17T23:33:50.6016492Z It's fields are defined by the RolloutSettings class below. 2024-12-17T23:33:50.6017215Z  2024-12-17T23:33:50.6018043Z The second part is a list of users who are explicitly opted in to the LF fleet. 2024-12-17T23:33:50.6019141Z The user list is also a comma separated list of additional features or 2024-12-17T23:33:50.6020433Z experiments which the user could be opted in to. 2024-12-17T23:33:50.6021157Z  2024-12-17T23:33:50.6021720Z The user list has the following rules: 2024-12-17T23:33:50.6022430Z  2024-12-17T23:33:50.6023127Z - Users are GitHub usernames, which must start with the @ prefix 2024-12-17T23:33:50.6024231Z - Each user is also a comma-separated list of features/experiments to enable 2024-12-17T23:33:50.6025248Z - A "#" prefix opts the user out of all experiments 2024-12-17T23:33:50.6025964Z  2024-12-17T23:33:50.6026578Z Example config: 2024-12-17T23:33:50.6027673Z  # A list of experiments that can be opted into. 2024-12-17T23:33:50.6028608Z  # This defines the behavior they'll induce when opted into. 2024-12-17T23:33:50.6029379Z  # Expected syntax is: 2024-12-17T23:33:50.6030315Z  # [experiment_name]: # Name of the experiment. Also used for the label prefix. 2024-12-17T23:33:50.6031531Z  # rollout_perc: [int] # % of workflows to run with this experiment when users are not opted in. 2024-12-17T23:33:50.6032443Z  2024-12-17T23:33:50.6033004Z  experiments: 2024-12-17T23:33:50.6033615Z  lf: 2024-12-17T23:33:50.6034156Z  rollout_percent: 25 2024-12-17T23:33:50.6034850Z  all_branches: false 2024-12-17T23:33:50.6035506Z  default: true 2024-12-17T23:33:50.6036118Z  --- 2024-12-17T23:33:50.6036638Z  2024-12-17T23:33:50.6037153Z  # Opt-ins: 2024-12-17T23:33:50.6037968Z  # Users can opt into the LF fleet by adding their GitHub username to this list 2024-12-17T23:33:50.6039258Z  # and specifying experiments to enable in a comma-separated list. 2024-12-17T23:33:50.6040307Z  # To always opt out of an experiment, prefix it with a "-". 2024-12-17T23:33:50.6041165Z  # Experiments should be from the above list. 2024-12-17T23:33:50.6041891Z  2024-12-17T23:33:50.6042445Z  @User1,-lf,split_build 2024-12-17T23:33:50.6043072Z  @User2,lf 2024-12-17T23:33:50.6043647Z  @User3,split_build 2024-12-17T23:33:50.6044291Z """ 2024-12-17T23:33:50.6044787Z  2024-12-17T23:33:50.6045297Z import json 2024-12-17T23:33:50.6045885Z import logging 2024-12-17T23:33:50.6046450Z import os 2024-12-17T23:33:50.6047004Z import random 2024-12-17T23:33:50.6047593Z import re 2024-12-17T23:33:50.6048294Z import sys 2024-12-17T23:33:50.6048964Z from argparse import ArgumentParser 2024-12-17T23:33:50.6049714Z from functools import lru_cache 2024-12-17T23:33:50.6050399Z from logging import LogRecord 2024-12-17T23:33:50.6051346Z from typing import Any, Dict, FrozenSet, Iterable, List, NamedTuple, Set, Tuple 2024-12-17T23:33:50.6052365Z from urllib.request import Request, urlopen 2024-12-17T23:33:50.6053061Z  2024-12-17T23:33:50.6053585Z import yaml 2024-12-17T23:33:50.6054172Z from github import Auth, Github 2024-12-17T23:33:50.6054867Z from github.Issue import Issue 2024-12-17T23:33:50.6055583Z  2024-12-17T23:33:50.6056025Z  2024-12-17T23:33:50.6056626Z DEFAULT_LABEL_PREFIX = "" # use meta runners 2024-12-17T23:33:50.6057610Z WORKFLOW_LABEL_LF = "lf." # use runners from the linux foundation 2024-12-17T23:33:50.6058663Z WORKFLOW_LABEL_LF_CANARY = "lf.c." # use canary runners from the linux foundation 2024-12-17T23:33:50.6059561Z  2024-12-17T23:33:50.6060215Z GITHUB_OUTPUT = os.getenv("GITHUB_OUTPUT", "") 2024-12-17T23:33:50.6060947Z GH_OUTPUT_KEY_AMI = "runner-ami" 2024-12-17T23:33:50.6061671Z GH_OUTPUT_KEY_LABEL_TYPE = "label-type" 2024-12-17T23:33:50.6062497Z OPT_OUT_LABEL = "no-runner-experiments" 2024-12-17T23:33:50.6063374Z  2024-12-17T23:33:50.6063916Z SETTING_EXPERIMENTS = "experiments" 2024-12-17T23:33:50.6064656Z  2024-12-17T23:33:50.6065163Z LF_FLEET_EXPERIMENT = "lf" 2024-12-17T23:33:50.6065816Z CANARY_FLEET_SUFFIX = ".c" 2024-12-17T23:33:50.6066493Z  2024-12-17T23:33:50.6066957Z  2024-12-17T23:33:50.6067471Z class Experiment(NamedTuple): 2024-12-17T23:33:50.6068199Z  rollout_perc: float = ( 2024-12-17T23:33:50.6069050Z  0 # Percentage of workflows to experiment on when user is not opted-in. 2024-12-17T23:33:50.6069947Z  ) 2024-12-17T23:33:50.6070574Z  all_branches: bool = ( 2024-12-17T23:33:50.6071385Z  False # If True, the experiment is also enabled on the exception branches 2024-12-17T23:33:50.6072218Z  ) 2024-12-17T23:33:50.6072887Z  default: bool = ( 2024-12-17T23:33:50.6073702Z  True # If True, the experiment is enabled by default for all queries 2024-12-17T23:33:50.6074518Z  ) 2024-12-17T23:33:50.6075093Z  2024-12-17T23:33:50.6075612Z  # Add more fields as needed 2024-12-17T23:33:50.6076228Z  2024-12-17T23:33:50.6076771Z  2024-12-17T23:33:50.6077283Z class Settings(NamedTuple): 2024-12-17T23:33:50.6077902Z  """ 2024-12-17T23:33:50.6078613Z  Settings for the experiments that can be opted into. 2024-12-17T23:33:50.6079367Z  """ 2024-12-17T23:33:50.6079870Z  2024-12-17T23:33:50.6080477Z  experiments: Dict[str, Experiment] = {} 2024-12-17T23:33:50.6081148Z  2024-12-17T23:33:50.6081638Z  2024-12-17T23:33:50.6082415Z class ColorFormatter(logging.Formatter): 2024-12-17T23:33:50.6083273Z  """Color codes the log messages based on the log level""" 2024-12-17T23:33:50.6084028Z  2024-12-17T23:33:50.6084586Z  COLORS = { 2024-12-17T23:33:50.6085197Z  "WARNING": "\033[33m", # Yellow 2024-12-17T23:33:50.6085861Z  "ERROR": "\033[31m", # Red 2024-12-17T23:33:50.6086578Z  "CRITICAL": "\033[31m", # Red 2024-12-17T23:33:50.6087278Z  "INFO": "\033[0m", # Reset 2024-12-17T23:33:50.6088277Z  "DEBUG": "\033[0m", # Reset 2024-12-17T23:33:50.6089061Z  } 2024-12-17T23:33:50.6089599Z  2024-12-17T23:33:50.6090167Z  def format(self, record: LogRecord) -> str: 2024-12-17T23:33:50.6091178Z  log_color = self.COLORS.get(record.levelname, "\033[0m") # Default to reset 2024-12-17T23:33:50.6092174Z  record.msg = f"{log_color}{record.msg}\033[0m" 2024-12-17T23:33:50.6092925Z  return super().format(record) 2024-12-17T23:33:50.6093681Z  2024-12-17T23:33:50.6094125Z  2024-12-17T23:33:50.6094659Z handler = logging.StreamHandler() 2024-12-17T23:33:50.6095700Z handler.setFormatter(ColorFormatter(fmt="%(levelname)-8s: %(message)s")) 2024-12-17T23:33:50.6096568Z  2024-12-17T23:33:50.6097171Z log = logging.getLogger(os.path.basename(__file__)) 2024-12-17T23:33:50.6098046Z log.addHandler(handler) 2024-12-17T23:33:50.6098683Z log.setLevel(logging.INFO) 2024-12-17T23:33:50.6099288Z  2024-12-17T23:33:50.6099866Z  2024-12-17T23:33:50.6100459Z def set_github_output(key: str, value: str) -> None: 2024-12-17T23:33:50.6101191Z  """ 2024-12-17T23:33:50.6101993Z  Defines outputs of the github action that invokes this script 2024-12-17T23:33:50.6102768Z  """ 2024-12-17T23:33:50.6103295Z  if not GITHUB_OUTPUT: 2024-12-17T23:33:50.6104686Z  # See https://github.blog/changelog/2022-10-11-github-actions-deprecating-save-state-and-set-output-commands/ for deprecation notice 2024-12-17T23:33:50.6106171Z  log.warning( 2024-12-17T23:33:50.6107242Z  "No env var found for GITHUB_OUTPUT, you must be running this code locally. Falling back to the deprecated print method." 2024-12-17T23:33:50.6108432Z  ) 2024-12-17T23:33:50.6109042Z  print(f"::set-output name={key}::{value}") 2024-12-17T23:33:50.6109717Z  return 2024-12-17T23:33:50.6110348Z  2024-12-17T23:33:50.6110901Z  with open(GITHUB_OUTPUT, "a") as f: 2024-12-17T23:33:50.6111616Z  log.info(f"Setting output: {key}='{value}'") 2024-12-17T23:33:50.6112439Z  f.write(f"{key}={value}\n") 2024-12-17T23:33:50.6113115Z  2024-12-17T23:33:50.6113558Z  2024-12-17T23:33:50.6114318Z def _str_comma_separated_to_set(value: str) -> FrozenSet[str]: 2024-12-17T23:33:50.6115156Z  return frozenset( 2024-12-17T23:33:50.6115938Z  filter(lambda itm: itm != "", map(str.strip, value.strip(" \n\t").split(","))) 2024-12-17T23:33:50.6116897Z  ) 2024-12-17T23:33:50.6117425Z  2024-12-17T23:33:50.6117859Z  2024-12-17T23:33:50.6118463Z def parse_args() -> Any: 2024-12-17T23:33:50.6119265Z  parser = ArgumentParser("Get dynamic rollout settings") 2024-12-17T23:33:50.6120383Z  parser.add_argument("--github-token", type=str, required=True, help="GitHub token") 2024-12-17T23:33:50.6121304Z  parser.add_argument( 2024-12-17T23:33:50.6121956Z  "--github-issue-repo", 2024-12-17T23:33:50.6122653Z  type=str, 2024-12-17T23:33:50.6123247Z  required=False, 2024-12-17T23:33:50.6124042Z  default="pytorch/test-infra", 2024-12-17T23:33:50.6124857Z  help="GitHub repo to get the issue", 2024-12-17T23:33:50.6125548Z  ) 2024-12-17T23:33:50.6126096Z  parser.add_argument( 2024-12-17T23:33:50.6126775Z  "--github-repo", 2024-12-17T23:33:50.6127383Z  type=str, 2024-12-17T23:33:50.6128114Z  required=True, 2024-12-17T23:33:50.6128880Z  help="GitHub repo where CI is running", 2024-12-17T23:33:50.6129663Z  ) 2024-12-17T23:33:50.6130209Z  parser.add_argument( 2024-12-17T23:33:50.6131113Z  "--github-issue", type=int, required=True, help="GitHub issue number" 2024-12-17T23:33:50.6131934Z  ) 2024-12-17T23:33:50.6132465Z  parser.add_argument( 2024-12-17T23:33:50.6133394Z  "--github-actor", type=str, required=True, help="GitHub triggering_actor" 2024-12-17T23:33:50.6134241Z  ) 2024-12-17T23:33:50.6134782Z  parser.add_argument( 2024-12-17T23:33:50.6135700Z  "--github-issue-owner", type=str, required=True, help="GitHub issue owner" 2024-12-17T23:33:50.6136583Z  ) 2024-12-17T23:33:50.6137078Z  parser.add_argument( 2024-12-17T23:33:50.6138013Z  "--github-branch", type=str, required=True, help="Current GitHub branch or tag" 2024-12-17T23:33:50.6138905Z  ) 2024-12-17T23:33:50.6139410Z  parser.add_argument( 2024-12-17T23:33:50.6140086Z  "--github-ref-type", 2024-12-17T23:33:50.6140739Z  type=str, 2024-12-17T23:33:50.6141303Z  required=True, 2024-12-17T23:33:50.6142047Z  help="Current GitHub ref type, branch or tag", 2024-12-17T23:33:50.6142782Z  ) 2024-12-17T23:33:50.6143294Z  parser.add_argument( 2024-12-17T23:33:50.6143987Z  "--eligible-experiments", 2024-12-17T23:33:50.6144705Z  type=_str_comma_separated_to_set, 2024-12-17T23:33:50.6145365Z  required=False, 2024-12-17T23:33:50.6146019Z  default="", 2024-12-17T23:33:50.6147343Z  help="comma separated list of experiments to check, if omitted all experiments marked with default=True are checked", 2024-12-17T23:33:50.6148453Z  ) 2024-12-17T23:33:50.6149006Z  parser.add_argument( 2024-12-17T23:33:50.6149665Z  "--pr-number", 2024-12-17T23:33:50.6150264Z  type=str, 2024-12-17T23:33:50.6150869Z  required=False, 2024-12-17T23:33:50.6151515Z  default="", 2024-12-17T23:33:50.6152188Z  help="the optional PR number where this is run", 2024-12-17T23:33:50.6152931Z  ) 2024-12-17T23:33:50.6153464Z  2024-12-17T23:33:50.6153980Z  return parser.parse_args() 2024-12-17T23:33:50.6154660Z  2024-12-17T23:33:50.6155176Z  2024-12-17T23:33:50.6155760Z def get_gh_client(github_token: str) -> Github: 2024-12-17T23:33:50.6156543Z  auth = Auth.Token(github_token) 2024-12-17T23:33:50.6157249Z  return Github(auth=auth) 2024-12-17T23:33:50.6157878Z  2024-12-17T23:33:50.6158395Z  2024-12-17T23:33:50.6159084Z def get_issue(gh: Github, repo: str, issue_num: int) -> Issue: 2024-12-17T23:33:50.6159910Z  repo = gh.get_repo(repo) 2024-12-17T23:33:50.6160658Z  return repo.get_issue(number=issue_num) 2024-12-17T23:33:50.6161357Z  2024-12-17T23:33:50.6161849Z  2024-12-17T23:33:50.6162377Z def get_potential_pr_author( 2024-12-17T23:33:50.6163257Z  github_token: str, repo: str, username: str, ref_type: str, ref_name: str 2024-12-17T23:33:50.6164133Z ) -> str: 2024-12-17T23:33:50.6165036Z  # If the trigger was a new tag added by a bot, this is a ciflow case 2024-12-17T23:33:50.6166243Z  # Fetch the actual username from the original PR. The PR number is 2024-12-17T23:33:50.6167187Z  # embedded in the tag name: ciflow// 2024-12-17T23:33:50.6168151Z  2024-12-17T23:33:50.6168727Z  gh = get_gh_client(github_token) 2024-12-17T23:33:50.6169378Z  2024-12-17T23:33:50.6170083Z  if username == "pytorch-bot[bot]" and ref_type == "tag": 2024-12-17T23:33:50.6170904Z  split_tag = ref_name.split("/") 2024-12-17T23:33:50.6171533Z  if ( 2024-12-17T23:33:50.6172168Z  len(split_tag) == 3 2024-12-17T23:33:50.6172863Z  and split_tag[0] == "ciflow" 2024-12-17T23:33:50.6173541Z  and split_tag[2].isnumeric() 2024-12-17T23:33:50.6174246Z  ): 2024-12-17T23:33:50.6174860Z  pr_number = split_tag[2] 2024-12-17T23:33:50.6175498Z  try: 2024-12-17T23:33:50.6176191Z  repository = gh.get_repo(repo) 2024-12-17T23:33:50.6177006Z  pull = repository.get_pull(number=int(pr_number)) 2024-12-17T23:33:50.6177783Z  except Exception as e: 2024-12-17T23:33:50.6178554Z  raise Exception( # noqa: TRY002 2024-12-17T23:33:50.6179413Z  f"issue with pull request {pr_number} from repo {repository}" 2024-12-17T23:33:50.6180201Z  ) from e 2024-12-17T23:33:50.6180894Z  return pull.user.login 2024-12-17T23:33:50.6181672Z  # In all other cases, return the original input username 2024-12-17T23:33:50.6182406Z  return username 2024-12-17T23:33:50.6183090Z  2024-12-17T23:33:50.6183534Z  2024-12-17T23:33:50.6184090Z def is_exception_branch(branch: str) -> bool: 2024-12-17T23:33:50.6184881Z  """ 2024-12-17T23:33:50.6185707Z  Branches that get opted out of experiments by default, until they're explicitly enabled. 2024-12-17T23:33:50.6186643Z  """ 2024-12-17T23:33:50.6187444Z  return branch.split("/")[0] in {"main", "nightly", "release", "landchecks"} 2024-12-17T23:33:50.6188473Z  2024-12-17T23:33:50.6188959Z  2024-12-17T23:33:50.6189576Z def load_yaml(yaml_text: str) -> Any: 2024-12-17T23:33:50.6190206Z  try: 2024-12-17T23:33:50.6190777Z  data = yaml.safe_load(yaml_text) 2024-12-17T23:33:50.6191547Z  return data 2024-12-17T23:33:50.6192129Z  except yaml.YAMLError: 2024-12-17T23:33:50.6192789Z  log.exception("Error loading YAML") 2024-12-17T23:33:50.6193548Z  raise 2024-12-17T23:33:50.6194062Z  2024-12-17T23:33:50.6194523Z  2024-12-17T23:33:50.6195391Z def extract_settings_user_opt_in_from_text(rollout_state: str) -> Tuple[str, str]: 2024-12-17T23:33:50.6196291Z  """ 2024-12-17T23:33:50.6197094Z  Extracts the text with settings, if any, and the opted in users from the rollout state. 2024-12-17T23:33:50.6198088Z  2024-12-17T23:33:50.6198807Z  If the issue body contains "---" then the text above that is the settings 2024-12-17T23:33:50.6199700Z  and the text below is the list of opted in users. 2024-12-17T23:33:50.6200528Z  2024-12-17T23:33:50.6201260Z  If it doesn't contain "---" then the settings are empty and the rest is the users. 2024-12-17T23:33:50.6202079Z  """ 2024-12-17T23:33:50.6202800Z  rollout_state_parts = rollout_state.split("---") 2024-12-17T23:33:50.6203558Z  if len(rollout_state_parts) >= 2: 2024-12-17T23:33:50.6204295Z  return rollout_state_parts[0], rollout_state_parts[1] 2024-12-17T23:33:50.6205151Z  else: 2024-12-17T23:33:50.6205853Z  return "", rollout_state 2024-12-17T23:33:50.6206451Z  2024-12-17T23:33:50.6207020Z  2024-12-17T23:33:50.6207566Z class UserOptins(Dict[str, List[str]]): 2024-12-17T23:33:50.6208335Z  """ 2024-12-17T23:33:50.6209146Z  Dictionary of users with a list of features they have opted into 2024-12-17T23:33:50.6209966Z  """ 2024-12-17T23:33:50.6210430Z  2024-12-17T23:33:50.6210992Z  2024-12-17T23:33:50.6211685Z def parse_user_opt_in_from_text(user_optin_text: str) -> UserOptins: 2024-12-17T23:33:50.6212565Z  """ 2024-12-17T23:33:50.6213451Z  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:33:50.6214437Z  2024-12-17T23:33:50.6215466Z  Users are GitHub usernames with the @ prefix. Each user is also a comma-separated list of features/experiments to enable. 2024-12-17T23:33:50.6216639Z  - Example line: "@User1,lf,split_build" 2024-12-17T23:33:50.6217532Z  - A "#" prefix indicates the user is opted out of all experiments 2024-12-17T23:33:50.6218373Z  2024-12-17T23:33:50.6218832Z  2024-12-17T23:33:50.6219323Z  """ 2024-12-17T23:33:50.6219905Z  optins = UserOptins() 2024-12-17T23:33:50.6220568Z  for user in user_optin_text.split("\n"): 2024-12-17T23:33:50.6221310Z  user = user.strip("\r\n\t -") 2024-12-17T23:33:50.6222092Z  if not user or not user.startswith("@"): 2024-12-17T23:33:50.6222833Z  # Not a valid user. Skip 2024-12-17T23:33:50.6223458Z  continue 2024-12-17T23:33:50.6224061Z  2024-12-17T23:33:50.6224574Z  if user: 2024-12-17T23:33:50.6225174Z  usr_name = user.split(",")[0].strip("@") 2024-12-17T23:33:50.6226095Z  optins[usr_name] = [exp.strip(" ") for exp in user.split(",")[1:]] 2024-12-17T23:33:50.6226918Z  2024-12-17T23:33:50.6227375Z  return optins 2024-12-17T23:33:50.6227977Z  2024-12-17T23:33:50.6228670Z  2024-12-17T23:33:50.6229296Z def is_valid_experiment_name(experiment_name: str) -> bool: 2024-12-17T23:33:50.6230117Z  """ 2024-12-17T23:33:50.6230717Z  Check if the experiment name is valid. 2024-12-17T23:33:50.6231407Z  A valid name: 2024-12-17T23:33:50.6232300Z  - Contains only alphanumeric characters and the special characters "_" & "-" 2024-12-17T23:33:50.6233478Z  - The special characters "_" & "-" shouldn't be the first or last characters 2024-12-17T23:33:50.6234314Z  - Cannot contain spaces 2024-12-17T23:33:50.6235029Z  """ 2024-12-17T23:33:50.6235547Z  2024-12-17T23:33:50.6236120Z  valid_char_regex = r"^[a-zA-Z0-9]([\w-]*[a-zA-Z0-9])?$" 2024-12-17T23:33:50.6237078Z  valid = bool(re.match(valid_char_regex, experiment_name)) 2024-12-17T23:33:50.6237857Z  2024-12-17T23:33:50.6238336Z  if valid: 2024-12-17T23:33:50.6238927Z  return True 2024-12-17T23:33:50.6239503Z  2024-12-17T23:33:50.6240002Z  log.error( 2024-12-17T23:33:50.6241676Z  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:33:50.6243431Z  ) 2024-12-17T23:33:50.6243967Z  return False 2024-12-17T23:33:50.6244524Z  2024-12-17T23:33:50.6245017Z  2024-12-17T23:33:50.6245704Z def parse_settings_from_text(settings_text: str) -> Settings: 2024-12-17T23:33:50.6246508Z  """ 2024-12-17T23:33:50.6247456Z  Parse the experiments from the issue body into a list of ExperimentSettings 2024-12-17T23:33:50.6248659Z  """ 2024-12-17T23:33:50.6249197Z  try: 2024-12-17T23:33:50.6249761Z  if settings_text: 2024-12-17T23:33:50.6250705Z  # Escape the backtick as well so that we can have the settings in a code block on the GH issue 2024-12-17T23:33:50.6251748Z  # for easy reading 2024-12-17T23:33:50.6252741Z  # Note: Using ascii for the backtick so that the cat step in _runner-determinator.yml doesn't choke on 2024-12-17T23:33:50.6253808Z  # the backtick character in shell commands. 2024-12-17T23:33:50.6254660Z  backtick = chr(96) # backtick character 2024-12-17T23:33:50.6255506Z  settings_text = settings_text.strip(f"\r\n\t{backtick} ") 2024-12-17T23:33:50.6256348Z  settings = load_yaml(settings_text) 2024-12-17T23:33:50.6257080Z  2024-12-17T23:33:50.6257857Z  # For now we just load experiments. We can expand this if/when we add more settings 2024-12-17T23:33:50.6258735Z  experiments = {} 2024-12-17T23:33:50.6259431Z  2024-12-17T23:33:50.6260149Z  for exp_name, exp_settings in settings.get(SETTING_EXPERIMENTS).items(): 2024-12-17T23:33:50.6261077Z  if not is_valid_experiment_name(exp_name): 2024-12-17T23:33:50.6262471Z  # 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:33:50.6263677Z  continue 2024-12-17T23:33:50.6264261Z  2024-12-17T23:33:50.6264827Z  valid_settings = {} 2024-12-17T23:33:50.6265523Z  for setting in exp_settings: 2024-12-17T23:33:50.6266251Z  if setting not in Experiment._fields: 2024-12-17T23:33:50.6267039Z  log.warning( 2024-12-17T23:33:50.6267946Z  f"Unexpected setting in experiment: {setting} = {exp_settings[setting]}" 2024-12-17T23:33:50.6268993Z  ) 2024-12-17T23:33:50.6269694Z  else: 2024-12-17T23:33:50.6270396Z  valid_settings[setting] = exp_settings[setting] 2024-12-17T23:33:50.6271118Z  2024-12-17T23:33:50.6271799Z  experiments[exp_name] = Experiment(**valid_settings) 2024-12-17T23:33:50.6272615Z  return Settings(experiments) 2024-12-17T23:33:50.6273263Z  2024-12-17T23:33:50.6273840Z  except Exception: 2024-12-17T23:33:50.6274479Z  log.exception("Failed to parse settings") 2024-12-17T23:33:50.6275176Z  2024-12-17T23:33:50.6275750Z  return Settings() 2024-12-17T23:33:50.6276339Z  2024-12-17T23:33:50.6276793Z  2024-12-17T23:33:50.6277474Z def parse_settings(rollout_state: str) -> Settings: 2024-12-17T23:33:50.6278189Z  """ 2024-12-17T23:33:50.6278792Z  Parse settings, if any, from the rollout state. 2024-12-17T23:33:50.6279568Z  2024-12-17T23:33:50.6280245Z  If the issue body contains "---" then the text above that is the settings 2024-12-17T23:33:50.6281156Z  and the text below is the list of opted in users. 2024-12-17T23:33:50.6281947Z  2024-12-17T23:33:50.6282695Z  If it doesn't contain "---" then the settings are empty and the default values are used. 2024-12-17T23:33:50.6283570Z  """ 2024-12-17T23:33:50.6284409Z  settings_text, _ = extract_settings_user_opt_in_from_text(rollout_state) 2024-12-17T23:33:50.6285323Z  return parse_settings_from_text(settings_text) 2024-12-17T23:33:50.6286010Z  2024-12-17T23:33:50.6286724Z  2024-12-17T23:33:50.6287310Z def parse_users(rollout_state: str) -> UserOptins: 2024-12-17T23:33:50.6288186Z  """ 2024-12-17T23:33:50.6288897Z  Parse users from the rollout state. 2024-12-17T23:33:50.6289572Z  2024-12-17T23:33:50.6289994Z  """ 2024-12-17T23:33:50.6290809Z  _, users_text = extract_settings_user_opt_in_from_text(rollout_state) 2024-12-17T23:33:50.6291738Z  return parse_user_opt_in_from_text(users_text) 2024-12-17T23:33:50.6292382Z  2024-12-17T23:33:50.6292950Z  2024-12-17T23:33:50.6293739Z def is_user_opted_in(user: str, user_optins: UserOptins, experiment_name: str) -> bool: 2024-12-17T23:33:50.6294617Z  """ 2024-12-17T23:33:50.6295285Z  Check if a user is opted into an experiment 2024-12-17T23:33:50.6296007Z  """ 2024-12-17T23:33:50.6296613Z  return experiment_name in user_optins.get(user, []) 2024-12-17T23:33:50.6297441Z  2024-12-17T23:33:50.6297911Z  2024-12-17T23:33:50.6298669Z def is_user_opted_out(user: str, user_optins: UserOptins, experiment_name: str) -> bool: 2024-12-17T23:33:50.6299694Z  """ 2024-12-17T23:33:50.6300344Z  Check if a user explicitly opted out of an experiment 2024-12-17T23:33:50.6301029Z  """ 2024-12-17T23:33:50.6301800Z  # if the experiment is prefixed with a "-", then it's an opt-out 2024-12-17T23:33:50.6302733Z  experiment_optout = "-" + experiment_name 2024-12-17T23:33:50.6303844Z  if experiment_optout not in user_optins.get(user, []): 2024-12-17T23:33:50.6304609Z  return False 2024-12-17T23:33:50.6305216Z  2024-12-17T23:33:50.6305879Z  if is_user_opted_in(user, user_optins, experiment_name): 2024-12-17T23:33:50.6306630Z  log.warning( 2024-12-17T23:33:50.6307659Z  f"User {user} is opted into experiment {experiment_name}, but also opted out of it. Defaulting to opting out" 2024-12-17T23:33:50.6308831Z  ) 2024-12-17T23:33:50.6309335Z  2024-12-17T23:33:50.6310038Z  return True 2024-12-17T23:33:50.6310644Z  2024-12-17T23:33:50.6311121Z  2024-12-17T23:33:50.6311621Z def get_runner_prefix( 2024-12-17T23:33:50.6312289Z  rollout_state: str, 2024-12-17T23:33:50.6312942Z  workflow_requestors: Iterable[str], 2024-12-17T23:33:50.6313634Z  branch: str, 2024-12-17T23:33:50.6314382Z  eligible_experiments: FrozenSet[str] = frozenset(), 2024-12-17T23:33:50.6315146Z  is_canary: bool = False, 2024-12-17T23:33:50.6315759Z ) -> str: 2024-12-17T23:33:50.6316399Z  settings = parse_settings(rollout_state) 2024-12-17T23:33:50.6317180Z  user_optins = parse_users(rollout_state) 2024-12-17T23:33:50.6317824Z  2024-12-17T23:33:50.6318384Z  fleet_prefix = "" 2024-12-17T23:33:50.6318994Z  prefixes = [] 2024-12-17T23:33:50.6319788Z  for experiment_name, experiment_settings in settings.experiments.items(): 2024-12-17T23:33:50.6320994Z  if not experiment_settings.all_branches and is_exception_branch(branch): 2024-12-17T23:33:50.6321903Z  log.info( 2024-12-17T23:33:50.6322738Z  f"Branch {branch} is an exception branch. Not enabling experiment {experiment_name}." 2024-12-17T23:33:50.6323708Z  ) 2024-12-17T23:33:50.6324274Z  continue 2024-12-17T23:33:50.6324806Z  2024-12-17T23:33:50.6325379Z  if eligible_experiments: 2024-12-17T23:33:50.6326145Z  if experiment_name not in eligible_experiments: 2024-12-17T23:33:50.6326915Z  exp_list = ", ".join(eligible_experiments) 2024-12-17T23:33:50.6327842Z  log.info( 2024-12-17T23:33:50.6329375Z  f"Skipping experiment '{experiment_name}', as it is not in the eligible_experiments list: {exp_list}" 2024-12-17T23:33:50.6330412Z  ) 2024-12-17T23:33:50.6331023Z  continue 2024-12-17T23:33:50.6331723Z  elif not experiment_settings.default: 2024-12-17T23:33:50.6332423Z  log.info( 2024-12-17T23:33:50.6333280Z  f"Skipping experiment '{experiment_name}', as it is not a default experiment" 2024-12-17T23:33:50.6334199Z  ) 2024-12-17T23:33:50.6334743Z  continue 2024-12-17T23:33:50.6335314Z  2024-12-17T23:33:50.6335971Z  # Is any workflow_requestor opted out to this experiment? 2024-12-17T23:33:50.6336740Z  opted_out_users = [ 2024-12-17T23:33:50.6337480Z  requestor 2024-12-17T23:33:50.6338183Z  for requestor in workflow_requestors 2024-12-17T23:33:50.6339039Z  if is_user_opted_out(requestor, user_optins, experiment_name) 2024-12-17T23:33:50.6339902Z  ] 2024-12-17T23:33:50.6340447Z  2024-12-17T23:33:50.6340948Z  if opted_out_users: 2024-12-17T23:33:50.6341644Z  log.info( 2024-12-17T23:33:50.6342429Z  f"{', '.join(opted_out_users)} have opted out of experiment {experiment_name}." 2024-12-17T23:33:50.6343268Z  ) 2024-12-17T23:33:50.6343889Z  continue 2024-12-17T23:33:50.6344424Z  2024-12-17T23:33:50.6345030Z  # Is any workflow_requestor opted in to this experiment? 2024-12-17T23:33:50.6345874Z  opted_in_users = [ 2024-12-17T23:33:50.6346458Z  requestor 2024-12-17T23:33:50.6347097Z  for requestor in workflow_requestors 2024-12-17T23:33:50.6348034Z  if is_user_opted_in(requestor, user_optins, experiment_name) 2024-12-17T23:33:50.6348771Z  ] 2024-12-17T23:33:50.6349288Z  2024-12-17T23:33:50.6350058Z  enabled = False 2024-12-17T23:33:50.6350642Z  if opted_in_users: 2024-12-17T23:33:50.6351279Z  log.info( 2024-12-17T23:33:50.6352132Z  f"{', '.join(opted_in_users)} have opted into experiment {experiment_name}." 2024-12-17T23:33:50.6352954Z  ) 2024-12-17T23:33:50.6353481Z  enabled = True 2024-12-17T23:33:50.6354135Z  2024-12-17T23:33:50.6354679Z  elif experiment_settings.rollout_perc: 2024-12-17T23:33:50.6355697Z  # If no user is opted in, then we randomly enable the experiment based on the rollout percentage 2024-12-17T23:33:50.6356937Z  if random.uniform(0, 100) <= experiment_settings.rollout_perc: 2024-12-17T23:33:50.6357764Z  log.info( 2024-12-17T23:33:50.6358787Z  f"Based on rollout percentage of {experiment_settings.rollout_perc}%, enabling experiment {experiment_name}." 2024-12-17T23:33:50.6359954Z  ) 2024-12-17T23:33:50.6360552Z  enabled = True 2024-12-17T23:33:50.6361218Z  2024-12-17T23:33:50.6361689Z  if enabled: 2024-12-17T23:33:50.6362310Z  label = experiment_name 2024-12-17T23:33:50.6363085Z  if experiment_name == LF_FLEET_EXPERIMENT: 2024-12-17T23:33:50.6364088Z  # We give some special treatment to the "lf" experiment since determines the fleet we use 2024-12-17T23:33:50.6365161Z  # - If it's enabled, then we always list it's prefix first 2024-12-17T23:33:50.6366324Z  # - If we're in the canary branch, then we append ".c" to the lf prefix 2024-12-17T23:33:50.6367213Z  if is_canary: 2024-12-17T23:33:50.6367850Z  label += CANARY_FLEET_SUFFIX 2024-12-17T23:33:50.6368770Z  fleet_prefix = label 2024-12-17T23:33:50.6369497Z  else: 2024-12-17T23:33:50.6370065Z  prefixes.append(label) 2024-12-17T23:33:50.6370767Z  2024-12-17T23:33:50.6371302Z  if len(prefixes) > 1: 2024-12-17T23:33:50.6371888Z  log.error( 2024-12-17T23:33:50.6373193Z  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:33:50.6374477Z  ) 2024-12-17T23:33:50.6375004Z  prefixes = prefixes[:1] 2024-12-17T23:33:50.6375697Z  2024-12-17T23:33:50.6376273Z  # Fleet always comes first 2024-12-17T23:33:50.6376890Z  if fleet_prefix: 2024-12-17T23:33:50.6377599Z  prefixes.insert(0, fleet_prefix) 2024-12-17T23:33:50.6378289Z  2024-12-17T23:33:50.6378860Z  return ".".join(prefixes) + "." if prefixes else "" 2024-12-17T23:33:50.6379673Z  2024-12-17T23:33:50.6380158Z  2024-12-17T23:33:50.6380922Z def get_rollout_state_from_issue(github_token: str, repo: str, issue_num: int) -> str: 2024-12-17T23:33:50.6381933Z  """ 2024-12-17T23:33:50.6382720Z  Gets the first comment of the issue, which contains the desired rollout state. 2024-12-17T23:33:50.6383603Z  2024-12-17T23:33:50.6384341Z  The default issue we use - https://github.com/pytorch/test-infra/issues/5132 2024-12-17T23:33:50.6385214Z  """ 2024-12-17T23:33:50.6385774Z  gh = get_gh_client(github_token) 2024-12-17T23:33:50.6386489Z  issue = get_issue(gh, repo, issue_num) 2024-12-17T23:33:50.6387328Z  return str(issue.get_comments()[0].body.strip("\n\t ")) 2024-12-17T23:33:50.6388094Z  2024-12-17T23:33:50.6388584Z  2024-12-17T23:33:50.6389364Z def download_json(url: str, headers: Dict[str, str], num_retries: int = 3) -> Any: 2024-12-17T23:33:50.6390495Z  for _ in range(num_retries): 2024-12-17T23:33:50.6391152Z  try: 2024-12-17T23:33:50.6391802Z  req = Request(url=url, headers=headers) 2024-12-17T23:33:50.6392635Z  content = urlopen(req, timeout=5).read().decode("utf-8") 2024-12-17T23:33:50.6393515Z  return json.loads(content) 2024-12-17T23:33:50.6394191Z  except Exception as e: 2024-12-17T23:33:50.6394921Z  log.warning(f"Could not download {url}: {e}") 2024-12-17T23:33:50.6395705Z  2024-12-17T23:33:50.6396402Z  log.warning(f"All {num_retries} retries exhausted, downloading {url} failed") 2024-12-17T23:33:50.6397278Z  return {} 2024-12-17T23:33:50.6397902Z  2024-12-17T23:33:50.6398340Z  2024-12-17T23:33:50.6398834Z @lru_cache(maxsize=None) 2024-12-17T23:33:50.6399823Z def get_pr_info(github_repo: str, github_token: str, pr_number: int) -> Dict[str, Any]: 2024-12-17T23:33:50.6400704Z  """ 2024-12-17T23:33:50.6401252Z  Dynamically get PR information 2024-12-17T23:33:50.6401967Z  """ 2024-12-17T23:33:50.6402603Z  github_api = f"https://api.github.com/repos/{github_repo}" 2024-12-17T23:33:50.6403386Z  headers = { 2024-12-17T23:33:50.6404116Z  "Accept": "application/vnd.github.v3+json", 2024-12-17T23:33:50.6404889Z  "Authorization": f"token {github_token}", 2024-12-17T23:33:50.6405535Z  } 2024-12-17T23:33:50.6406216Z  json_response: Dict[str, Any] = download_json( 2024-12-17T23:33:50.6407147Z  url=f"{github_api}/issues/{pr_number}", 2024-12-17T23:33:50.6407848Z  headers=headers, 2024-12-17T23:33:50.6409136Z  ) 2024-12-17T23:33:50.6409651Z  2024-12-17T23:33:50.6410154Z  if not json_response: 2024-12-17T23:33:50.6411003Z  log.warning(f"Failed to get the labels for #{pr_number}") 2024-12-17T23:33:50.6411795Z  return {} 2024-12-17T23:33:50.6412320Z  2024-12-17T23:33:50.6412884Z  return json_response 2024-12-17T23:33:50.6413495Z  2024-12-17T23:33:50.6413927Z  2024-12-17T23:33:50.6414741Z def get_labels(github_repo: str, github_token: str, pr_number: int) -> Set[str]: 2024-12-17T23:33:50.6415641Z  """ 2024-12-17T23:33:50.6416304Z  Dynamically get the latest list of labels from the pull request 2024-12-17T23:33:50.6417171Z  """ 2024-12-17T23:33:50.6417845Z  pr_info = get_pr_info(github_repo, github_token, pr_number) 2024-12-17T23:33:50.6418570Z  return { 2024-12-17T23:33:50.6419401Z  label.get("name") for label in pr_info.get("labels", []) if label.get("name") 2024-12-17T23:33:50.6420264Z  } 2024-12-17T23:33:50.6420717Z  2024-12-17T23:33:50.6421245Z  2024-12-17T23:33:50.6421754Z def main() -> None: 2024-12-17T23:33:50.6422307Z  args = parse_args() 2024-12-17T23:33:50.6422979Z  2024-12-17T23:33:50.6423542Z  runner_label_prefix = DEFAULT_LABEL_PREFIX 2024-12-17T23:33:50.6424189Z  2024-12-17T23:33:50.6424790Z  # Check if the PR is opt-out 2024-12-17T23:33:50.6425437Z  if args.pr_number: 2024-12-17T23:33:50.6426272Z  labels = get_labels(args.github_repo, args.github_token, int(args.pr_number)) 2024-12-17T23:33:50.6427238Z  if OPT_OUT_LABEL in labels: 2024-12-17T23:33:50.6427889Z  log.info( 2024-12-17T23:33:50.6428761Z  f"Opt-out runner determinator because #{args.pr_number} has {OPT_OUT_LABEL} label" 2024-12-17T23:33:50.6429723Z  ) 2024-12-17T23:33:50.6430659Z  set_github_output(GH_OUTPUT_KEY_LABEL_TYPE, runner_label_prefix) 2024-12-17T23:33:50.6431499Z  sys.exit() 2024-12-17T23:33:50.6432128Z  2024-12-17T23:33:50.6432607Z  try: 2024-12-17T23:33:50.6433216Z  rollout_state = get_rollout_state_from_issue( 2024-12-17T23:33:50.6434141Z  args.github_token, args.github_issue_repo, args.github_issue 2024-12-17T23:33:50.6434928Z  ) 2024-12-17T23:33:50.6435446Z  2024-12-17T23:33:50.6436062Z  username = get_potential_pr_author( 2024-12-17T23:33:50.6436717Z  args.github_token, 2024-12-17T23:33:50.6437361Z  args.github_repo, 2024-12-17T23:33:50.6438099Z  args.github_actor, 2024-12-17T23:33:50.6438733Z  args.github_ref_type, 2024-12-17T23:33:50.6439374Z  args.github_branch, 2024-12-17T23:33:50.6440090Z  ) 2024-12-17T23:33:50.6440581Z  2024-12-17T23:33:50.6441199Z  is_canary = args.github_repo == "pytorch/pytorch-canary" 2024-12-17T23:33:50.6442028Z  2024-12-17T23:33:50.6442589Z  runner_label_prefix = get_runner_prefix( 2024-12-17T23:33:50.6443292Z  rollout_state, 2024-12-17T23:33:50.6444027Z  (args.github_issue_owner, username), 2024-12-17T23:33:50.6444710Z  args.github_branch, 2024-12-17T23:33:50.6445367Z  args.eligible_experiments, 2024-12-17T23:33:50.6446126Z  is_canary, 2024-12-17T23:33:50.6446674Z  ) 2024-12-17T23:33:50.6447273Z  2024-12-17T23:33:50.6447881Z  except Exception as e: 2024-12-17T23:33:50.6448776Z  log.error( 2024-12-17T23:33:50.6449662Z  f"Failed to get issue. Defaulting to Meta runners and no experiments. Exception: {e}" 2024-12-17T23:33:50.6450703Z  ) 2024-12-17T23:33:50.6451183Z  2024-12-17T23:33:50.6451850Z  set_github_output(GH_OUTPUT_KEY_LABEL_TYPE, runner_label_prefix) 2024-12-17T23:33:50.6452761Z  2024-12-17T23:33:50.6453233Z  2024-12-17T23:33:50.6453690Z if __name__ == "__main__": 2024-12-17T23:33:50.6454371Z  main() 2024-12-17T23:33:50.6454884Z  2024-12-17T23:33:50.6455319Z EOF 2024-12-17T23:33:50.6455878Z  2024-12-17T23:33:50.6456352Z cat runner_determinator.py 2024-12-17T23:33:50.6964842Z shell: /usr/bin/bash -e {0} 2024-12-17T23:33:50.6965747Z env: 2024-12-17T23:33:50.6966624Z GITHUB_TOKEN: *** 2024-12-17T23:33:50.6967232Z ISSUE_NUMBER: 5132 2024-12-17T23:33:50.6967763Z TRIGGERING_ACTOR: malfet 2024-12-17T23:33:50.6969023Z ISSUE_OWNER: 2024-12-17T23:33:50.6969638Z CHECK_EXPERIMENTS: 2024-12-17T23:33:50.6970147Z PR_NUMBER: 2024-12-17T23:33:50.6970729Z ##[endgroup] 2024-12-17T23:33:50.7196722Z # flake8: noqa: G004 2024-12-17T23:33:50.7197254Z 2024-12-17T23:33:50.7197764Z # Note: Copies of this script in runner_determinator.py and _runner-determinator.yml 2024-12-17T23:33:50.7198875Z # must be kept in sync. You can do it easily by running the following command: 2024-12-17T23:33:50.7199758Z # python .github/scripts/update_runner_determinator.py 2024-12-17T23:33:50.7200346Z 2024-12-17T23:33:50.7200558Z """ 2024-12-17T23:33:50.7201260Z This runner determinator is used to determine which set of runners to run a 2024-12-17T23:33:50.7202241Z GitHub job on. It uses the first comment of a GitHub issue (by default 2024-12-17T23:33:50.7203309Z https://github.com/pytorch/test-infra/issues/5132) to define the configuration 2024-12-17T23:33:50.7204284Z of which runners should be used to run which job. 2024-12-17T23:33:50.7204729Z 2024-12-17T23:33:50.7205193Z The configuration has two parts, the settings and a list of opted-in users, 2024-12-17T23:33:50.7206245Z separated by a line containing "---". If the line is not present, the 2024-12-17T23:33:50.7207503Z settings are considered to be empty with only the second part, the user 2024-12-17T23:33:50.7208684Z list, defined. 2024-12-17T23:33:50.7209070Z 2024-12-17T23:33:50.7209525Z The first part is a YAML block that defines the rollout settings. This can be 2024-12-17T23:33:50.7210599Z used to define any settings that are needed to determine which runners to use. 2024-12-17T23:33:50.7211530Z It's fields are defined by the RolloutSettings class below. 2024-12-17T23:33:50.7212078Z 2024-12-17T23:33:50.7212562Z The second part is a list of users who are explicitly opted in to the LF fleet. 2024-12-17T23:33:50.7213540Z The user list is also a comma separated list of additional features or 2024-12-17T23:33:50.7214385Z experiments which the user could be opted in to. 2024-12-17T23:33:50.7214912Z 2024-12-17T23:33:50.7215217Z The user list has the following rules: 2024-12-17T23:33:50.7215603Z 2024-12-17T23:33:50.7215953Z - Users are GitHub usernames, which must start with the @ prefix 2024-12-17T23:33:50.7216919Z - Each user is also a comma-separated list of features/experiments to enable 2024-12-17T23:33:50.7217909Z - A "#" prefix opts the user out of all experiments 2024-12-17T23:33:50.7218349Z 2024-12-17T23:33:50.7218600Z Example config: 2024-12-17T23:33:50.7219115Z # A list of experiments that can be opted into. 2024-12-17T23:33:50.7220004Z # This defines the behavior they'll induce when opted into. 2024-12-17T23:33:50.7220739Z # Expected syntax is: 2024-12-17T23:33:50.7221457Z # [experiment_name]: # Name of the experiment. Also used for the label prefix. 2024-12-17T23:33:50.7222634Z # rollout_perc: [int] # % of workflows to run with this experiment when users are not opted in. 2024-12-17T23:33:50.7223295Z 2024-12-17T23:33:50.7223728Z experiments: 2024-12-17T23:33:50.7224216Z lf: 2024-12-17T23:33:50.7224798Z rollout_percent: 25 2024-12-17T23:33:50.7225385Z all_branches: false 2024-12-17T23:33:50.7225913Z default: true 2024-12-17T23:33:50.7226506Z --- 2024-12-17T23:33:50.7226755Z 2024-12-17T23:33:50.7227005Z # Opt-ins: 2024-12-17T23:33:50.7227658Z # Users can opt into the LF fleet by adding their GitHub username to this list 2024-12-17T23:33:50.7228735Z # and specifying experiments to enable in a comma-separated list. 2024-12-17T23:33:50.7229644Z # To always opt out of an experiment, prefix it with a "-". 2024-12-17T23:33:50.7230364Z # Experiments should be from the above list. 2024-12-17T23:33:50.7230921Z 2024-12-17T23:33:50.7231138Z @User1,-lf,split_build 2024-12-17T23:33:50.7231709Z @User2,lf 2024-12-17T23:33:50.7232145Z @User3,split_build 2024-12-17T23:33:50.7232743Z """ 2024-12-17T23:33:50.7232986Z 2024-12-17T23:33:50.7233228Z import json 2024-12-17T23:33:50.7233654Z import logging 2024-12-17T23:33:50.7234248Z import os 2024-12-17T23:33:50.7234715Z import random 2024-12-17T23:33:50.7235142Z import re 2024-12-17T23:33:50.7235708Z import sys 2024-12-17T23:33:50.7236207Z from argparse import ArgumentParser 2024-12-17T23:33:50.7236784Z from functools import lru_cache 2024-12-17T23:33:50.7237486Z from logging import LogRecord 2024-12-17T23:33:50.7238290Z from typing import Any, Dict, FrozenSet, Iterable, List, NamedTuple, Set, Tuple 2024-12-17T23:33:50.7239126Z from urllib.request import Request, urlopen 2024-12-17T23:33:50.7239665Z 2024-12-17T23:33:50.7239865Z import yaml 2024-12-17T23:33:50.7240405Z from github import Auth, Github 2024-12-17T23:33:50.7240950Z from github.Issue import Issue 2024-12-17T23:33:50.7241427Z 2024-12-17T23:33:50.7241434Z 2024-12-17T23:33:50.7241722Z DEFAULT_LABEL_PREFIX = "" # use meta runners 2024-12-17T23:33:50.7242525Z WORKFLOW_LABEL_LF = "lf." # use runners from the linux foundation 2024-12-17T23:33:50.7243571Z WORKFLOW_LABEL_LF_CANARY = "lf.c." # use canary runners from the linux foundation 2024-12-17T23:33:50.7244202Z 2024-12-17T23:33:50.7244472Z GITHUB_OUTPUT = os.getenv("GITHUB_OUTPUT", "") 2024-12-17T23:33:50.7245343Z GH_OUTPUT_KEY_AMI = "runner-ami" 2024-12-17T23:33:50.7246030Z GH_OUTPUT_KEY_LABEL_TYPE = "label-type" 2024-12-17T23:33:50.7246685Z OPT_OUT_LABEL = "no-runner-experiments" 2024-12-17T23:33:50.7247109Z 2024-12-17T23:33:50.7247337Z SETTING_EXPERIMENTS = "experiments" 2024-12-17T23:33:50.7247727Z 2024-12-17T23:33:50.7248366Z LF_FLEET_EXPERIMENT = "lf" 2024-12-17T23:33:50.7249016Z CANARY_FLEET_SUFFIX = ".c" 2024-12-17T23:33:50.7249386Z 2024-12-17T23:33:50.7249394Z 2024-12-17T23:33:50.7249643Z class Experiment(NamedTuple): 2024-12-17T23:33:50.7250296Z rollout_perc: float = ( 2024-12-17T23:33:50.7251051Z 0 # Percentage of workflows to experiment on when user is not opted-in. 2024-12-17T23:33:50.7251869Z ) 2024-12-17T23:33:50.7252392Z all_branches: bool = ( 2024-12-17T23:33:50.7253137Z False # If True, the experiment is also enabled on the exception branches 2024-12-17T23:33:50.7253950Z ) 2024-12-17T23:33:50.7254464Z default: bool = ( 2024-12-17T23:33:50.7255142Z True # If True, the experiment is enabled by default for all queries 2024-12-17T23:33:50.7255918Z ) 2024-12-17T23:33:50.7256151Z 2024-12-17T23:33:50.7256467Z # Add more fields as needed 2024-12-17T23:33:50.7256841Z 2024-12-17T23:33:50.7256849Z 2024-12-17T23:33:50.7257125Z class Settings(NamedTuple): 2024-12-17T23:33:50.7257653Z """ 2024-12-17T23:33:50.7258267Z Settings for the experiments that can be opted into. 2024-12-17T23:33:50.7258993Z """ 2024-12-17T23:33:50.7259225Z 2024-12-17T23:33:50.7259464Z experiments: Dict[str, Experiment] = {} 2024-12-17T23:33:50.7259889Z 2024-12-17T23:33:50.7259895Z 2024-12-17T23:33:50.7260204Z class ColorFormatter(logging.Formatter): 2024-12-17T23:33:50.7260981Z """Color codes the log messages based on the log level""" 2024-12-17T23:33:50.7261649Z 2024-12-17T23:33:50.7261873Z COLORS = { 2024-12-17T23:33:50.7262462Z "WARNING": "\033[33m", # Yellow 2024-12-17T23:33:50.7263117Z "ERROR": "\033[31m", # Red 2024-12-17T23:33:50.7263691Z "CRITICAL": "\033[31m", # Red 2024-12-17T23:33:50.7264340Z "INFO": "\033[0m", # Reset 2024-12-17T23:33:50.7264973Z "DEBUG": "\033[0m", # Reset 2024-12-17T23:33:50.7265514Z } 2024-12-17T23:33:50.7265778Z 2024-12-17T23:33:50.7266122Z def format(self, record: LogRecord) -> str: 2024-12-17T23:33:50.7267022Z log_color = self.COLORS.get(record.levelname, "\033[0m") # Default to reset 2024-12-17T23:33:50.7267896Z record.msg = f"{log_color}{record.msg}\033[0m" 2024-12-17T23:33:50.7268661Z return super().format(record) 2024-12-17T23:33:50.7269090Z 2024-12-17T23:33:50.7269098Z 2024-12-17T23:33:50.7269327Z handler = logging.StreamHandler() 2024-12-17T23:33:50.7270161Z handler.setFormatter(ColorFormatter(fmt="%(levelname)-8s: %(message)s")) 2024-12-17T23:33:50.7270796Z 2024-12-17T23:33:50.7271152Z log = logging.getLogger(os.path.basename(__file__)) 2024-12-17T23:33:50.7271874Z log.addHandler(handler) 2024-12-17T23:33:50.7272448Z log.setLevel(logging.INFO) 2024-12-17T23:33:50.7272762Z 2024-12-17T23:33:50.7272769Z 2024-12-17T23:33:50.7273121Z def set_github_output(key: str, value: str) -> None: 2024-12-17T23:33:50.7273814Z """ 2024-12-17T23:33:50.7274471Z Defines outputs of the github action that invokes this script 2024-12-17T23:33:50.7275220Z """ 2024-12-17T23:33:50.7275712Z if not GITHUB_OUTPUT: 2024-12-17T23:33:50.7276911Z # See https://github.blog/changelog/2022-10-11-github-actions-deprecating-save-state-and-set-output-commands/ for deprecation notice 2024-12-17T23:33:50.7278193Z log.warning( 2024-12-17T23:33:50.7279210Z "No env var found for GITHUB_OUTPUT, you must be running this code locally. Falling back to the deprecated print method." 2024-12-17T23:33:50.7280281Z ) 2024-12-17T23:33:50.7290386Z print(f"::set-output name={key}::{value}") 2024-12-17T23:33:50.7291106Z return 2024-12-17T23:33:50.7291414Z 2024-12-17T23:33:50.7291670Z with open(GITHUB_OUTPUT, "a") as f: 2024-12-17T23:33:50.7292674Z log.info(f"Setting output: {key}='{value}'") 2024-12-17T23:33:50.7293363Z f.write(f"{key}={value}\n") 2024-12-17T23:33:50.7293785Z 2024-12-17T23:33:50.7293792Z 2024-12-17T23:33:50.7294134Z def _str_comma_separated_to_set(value: str) -> FrozenSet[str]: 2024-12-17T23:33:50.7294955Z return frozenset( 2024-12-17T23:33:50.7295648Z filter(lambda itm: itm != "", map(str.strip, value.strip(" \n\t").split(","))) 2024-12-17T23:33:50.7296458Z ) 2024-12-17T23:33:50.7296681Z 2024-12-17T23:33:50.7296687Z 2024-12-17T23:33:50.7297028Z def parse_args() -> Any: 2024-12-17T23:33:50.7297684Z parser = ArgumentParser("Get dynamic rollout settings") 2024-12-17T23:33:50.7298683Z parser.add_argument("--github-token", type=str, required=True, help="GitHub token") 2024-12-17T23:33:50.7299668Z parser.add_argument( 2024-12-17T23:33:50.7300258Z "--github-issue-repo", 2024-12-17T23:33:50.7300794Z type=str, 2024-12-17T23:33:50.7301379Z required=False, 2024-12-17T23:33:50.7301947Z default="pytorch/test-infra", 2024-12-17T23:33:50.7302589Z help="GitHub repo to get the issue", 2024-12-17T23:33:50.7303819Z ) 2024-12-17T23:33:50.7304324Z parser.add_argument( 2024-12-17T23:33:50.7304915Z "--github-repo", 2024-12-17T23:33:50.7305552Z type=str, 2024-12-17T23:33:50.7306038Z required=True, 2024-12-17T23:33:50.7306629Z help="GitHub repo where CI is running", 2024-12-17T23:33:50.7307345Z ) 2024-12-17T23:33:50.7307783Z parser.add_argument( 2024-12-17T23:33:50.7308512Z "--github-issue", type=int, required=True, help="GitHub issue number" 2024-12-17T23:33:50.7309356Z ) 2024-12-17T23:33:50.7309802Z parser.add_argument( 2024-12-17T23:33:50.7310760Z "--github-actor", type=str, required=True, help="GitHub triggering_actor" 2024-12-17T23:33:50.7311671Z ) 2024-12-17T23:33:50.7312146Z parser.add_argument( 2024-12-17T23:33:50.7312910Z "--github-issue-owner", type=str, required=True, help="GitHub issue owner" 2024-12-17T23:33:50.7313794Z ) 2024-12-17T23:33:50.7314249Z parser.add_argument( 2024-12-17T23:33:50.7315016Z "--github-branch", type=str, required=True, help="Current GitHub branch or tag" 2024-12-17T23:33:50.7315903Z ) 2024-12-17T23:33:50.7316364Z parser.add_argument( 2024-12-17T23:33:50.7316917Z "--github-ref-type", 2024-12-17T23:33:50.7317573Z type=str, 2024-12-17T23:33:50.7318038Z required=True, 2024-12-17T23:33:50.7318630Z help="Current GitHub ref type, branch or tag", 2024-12-17T23:33:50.7319369Z ) 2024-12-17T23:33:50.7319811Z parser.add_argument( 2024-12-17T23:33:50.7320371Z "--eligible-experiments", 2024-12-17T23:33:50.7321078Z type=_str_comma_separated_to_set, 2024-12-17T23:33:50.7321679Z required=False, 2024-12-17T23:33:50.7322203Z default="", 2024-12-17T23:33:50.7323261Z help="comma separated list of experiments to check, if omitted all experiments marked with default=True are checked", 2024-12-17T23:33:50.7324278Z ) 2024-12-17T23:33:50.7324742Z parser.add_argument( 2024-12-17T23:33:50.7325391Z "--pr-number", 2024-12-17T23:33:50.7325883Z type=str, 2024-12-17T23:33:50.7326386Z required=False, 2024-12-17T23:33:50.7326997Z default="", 2024-12-17T23:33:50.7327539Z help="the optional PR number where this is run", 2024-12-17T23:33:50.7328612Z ) 2024-12-17T23:33:50.7328858Z 2024-12-17T23:33:50.7329235Z return parser.parse_args() 2024-12-17T23:33:50.7329602Z 2024-12-17T23:33:50.7329609Z 2024-12-17T23:33:50.7329917Z def get_gh_client(github_token: str) -> Github: 2024-12-17T23:33:50.7330599Z auth = Auth.Token(github_token) 2024-12-17T23:33:50.7331288Z return Github(auth=auth) 2024-12-17T23:33:50.7331635Z 2024-12-17T23:33:50.7331643Z 2024-12-17T23:33:50.7332015Z def get_issue(gh: Github, repo: str, issue_num: int) -> Issue: 2024-12-17T23:33:50.7332741Z repo = gh.get_repo(repo) 2024-12-17T23:33:50.7333649Z return repo.get_issue(number=issue_num) 2024-12-17T23:33:50.7334064Z 2024-12-17T23:33:50.7334071Z 2024-12-17T23:33:50.7334350Z def get_potential_pr_author( 2024-12-17T23:33:50.7335067Z github_token: str, repo: str, username: str, ref_type: str, ref_name: str 2024-12-17T23:33:50.7335934Z ) -> str: 2024-12-17T23:33:50.7336574Z # If the trigger was a new tag added by a bot, this is a ciflow case 2024-12-17T23:33:50.7337460Z # Fetch the actual username from the original PR. The PR number is 2024-12-17T23:33:50.7338382Z # embedded in the tag name: ciflow// 2024-12-17T23:33:50.7338889Z 2024-12-17T23:33:50.7339116Z gh = get_gh_client(github_token) 2024-12-17T23:33:50.7339491Z 2024-12-17T23:33:50.7339822Z if username == "pytorch-bot[bot]" and ref_type == "tag": 2024-12-17T23:33:50.7340662Z split_tag = ref_name.split("/") 2024-12-17T23:33:50.7341294Z if ( 2024-12-17T23:33:50.7341775Z len(split_tag) == 3 2024-12-17T23:33:50.7342422Z and split_tag[0] == "ciflow" 2024-12-17T23:33:50.7343071Z and split_tag[2].isnumeric() 2024-12-17T23:33:50.7343650Z ): 2024-12-17T23:33:50.7344193Z pr_number = split_tag[2] 2024-12-17T23:33:50.7344783Z try: 2024-12-17T23:33:50.7345292Z repository = gh.get_repo(repo) 2024-12-17T23:33:50.7346083Z pull = repository.get_pull(number=int(pr_number)) 2024-12-17T23:33:50.7346801Z except Exception as e: 2024-12-17T23:33:50.7347404Z raise Exception( # noqa: TRY002 2024-12-17T23:33:50.7348245Z f"issue with pull request {pr_number} from repo {repository}" 2024-12-17T23:33:50.7349002Z ) from e 2024-12-17T23:33:50.7349546Z return pull.user.login 2024-12-17T23:33:50.7350450Z # In all other cases, return the original input username 2024-12-17T23:33:50.7351184Z return username 2024-12-17T23:33:50.7351464Z 2024-12-17T23:33:50.7351477Z 2024-12-17T23:33:50.7351778Z def is_exception_branch(branch: str) -> bool: 2024-12-17T23:33:50.7352472Z """ 2024-12-17T23:33:50.7353227Z Branches that get opted out of experiments by default, until they're explicitly enabled. 2024-12-17T23:33:50.7354111Z """ 2024-12-17T23:33:50.7354817Z return branch.split("/")[0] in {"main", "nightly", "release", "landchecks"} 2024-12-17T23:33:50.7355423Z 2024-12-17T23:33:50.7355430Z 2024-12-17T23:33:50.7355667Z def load_yaml(yaml_text: str) -> Any: 2024-12-17T23:33:50.7356267Z try: 2024-12-17T23:33:50.7356829Z data = yaml.safe_load(yaml_text) 2024-12-17T23:33:50.7357422Z return data 2024-12-17T23:33:50.7357946Z except yaml.YAMLError: 2024-12-17T23:33:50.7358612Z log.exception("Error loading YAML") 2024-12-17T23:33:50.7359223Z raise 2024-12-17T23:33:50.7359516Z 2024-12-17T23:33:50.7359523Z 2024-12-17T23:33:50.7359960Z def extract_settings_user_opt_in_from_text(rollout_state: str) -> Tuple[str, str]: 2024-12-17T23:33:50.7360914Z """ 2024-12-17T23:33:50.7361621Z Extracts the text with settings, if any, and the opted in users from the rollout state. 2024-12-17T23:33:50.7362311Z 2024-12-17T23:33:50.7362685Z If the issue body contains "---" then the text above that is the settings 2024-12-17T23:33:50.7363639Z and the text below is the list of opted in users. 2024-12-17T23:33:50.7364101Z 2024-12-17T23:33:50.7364511Z If it doesn't contain "---" then the settings are empty and the rest is the users. 2024-12-17T23:33:50.7365303Z """ 2024-12-17T23:33:50.7365919Z rollout_state_parts = rollout_state.split("---") 2024-12-17T23:33:50.7366619Z if len(rollout_state_parts) >= 2: 2024-12-17T23:33:50.7367315Z return rollout_state_parts[0], rollout_state_parts[1] 2024-12-17T23:33:50.7368528Z else: 2024-12-17T23:33:50.7369030Z return "", rollout_state 2024-12-17T23:33:50.7369427Z 2024-12-17T23:33:50.7369436Z 2024-12-17T23:33:50.7369670Z class UserOptins(Dict[str, List[str]]): 2024-12-17T23:33:50.7370605Z """ 2024-12-17T23:33:50.7371249Z Dictionary of users with a list of features they have opted into 2024-12-17T23:33:50.7371961Z """ 2024-12-17T23:33:50.7372326Z 2024-12-17T23:33:50.7372333Z 2024-12-17T23:33:50.7372708Z def parse_user_opt_in_from_text(user_optin_text: str) -> UserOptins: 2024-12-17T23:33:50.7373483Z """ 2024-12-17T23:33:50.7374245Z 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:33:50.7375108Z 2024-12-17T23:33:50.7375794Z Users are GitHub usernames with the @ prefix. Each user is also a comma-separated list of features/experiments to enable. 2024-12-17T23:33:50.7376903Z - Example line: "@User1,lf,split_build" 2024-12-17T23:33:50.7377759Z - A "#" prefix indicates the user is opted out of all experiments 2024-12-17T23:33:50.7378313Z 2024-12-17T23:33:50.7378319Z 2024-12-17T23:33:50.7378515Z """ 2024-12-17T23:33:50.7378993Z optins = UserOptins() 2024-12-17T23:33:50.7379658Z for user in user_optin_text.split("\n"): 2024-12-17T23:33:50.7380307Z user = user.strip("\r\n\t -") 2024-12-17T23:33:50.7380960Z if not user or not user.startswith("@"): 2024-12-17T23:33:50.7381685Z # Not a valid user. Skip 2024-12-17T23:33:50.7382262Z continue 2024-12-17T23:33:50.7382573Z 2024-12-17T23:33:50.7382767Z if user: 2024-12-17T23:33:50.7383371Z usr_name = user.split(",")[0].strip("@") 2024-12-17T23:33:50.7384164Z optins[usr_name] = [exp.strip(" ") for exp in user.split(",")[1:]] 2024-12-17T23:33:50.7384735Z 2024-12-17T23:33:50.7384952Z return optins 2024-12-17T23:33:50.7385227Z 2024-12-17T23:33:50.7385234Z 2024-12-17T23:33:50.7385631Z def is_valid_experiment_name(experiment_name: str) -> bool: 2024-12-17T23:33:50.7386477Z """ 2024-12-17T23:33:50.7387030Z Check if the experiment name is valid. 2024-12-17T23:33:50.7387724Z A valid name: 2024-12-17T23:33:50.7388455Z - Contains only alphanumeric characters and the special characters "_" & "-" 2024-12-17T23:33:50.7389531Z - The special characters "_" & "-" shouldn't be the first or last characters 2024-12-17T23:33:50.7390405Z - Cannot contain spaces 2024-12-17T23:33:50.7391001Z """ 2024-12-17T23:33:50.7391236Z 2024-12-17T23:33:50.7391534Z valid_char_regex = r"^[a-zA-Z0-9]([\w-]*[a-zA-Z0-9])?$" 2024-12-17T23:33:50.7392386Z valid = bool(re.match(valid_char_regex, experiment_name)) 2024-12-17T23:33:50.7392893Z 2024-12-17T23:33:50.7393139Z if valid: 2024-12-17T23:33:50.7393583Z return True 2024-12-17T23:33:50.7393875Z 2024-12-17T23:33:50.7394134Z log.error( 2024-12-17T23:33:50.7395750Z 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:33:50.7397384Z ) 2024-12-17T23:33:50.7397884Z return False 2024-12-17T23:33:50.7398193Z 2024-12-17T23:33:50.7398200Z 2024-12-17T23:33:50.7398581Z def parse_settings_from_text(settings_text: str) -> Settings: 2024-12-17T23:33:50.7399282Z """ 2024-12-17T23:33:50.7400019Z Parse the experiments from the issue body into a list of ExperimentSettings 2024-12-17T23:33:50.7400869Z """ 2024-12-17T23:33:50.7401287Z try: 2024-12-17T23:33:50.7401822Z if settings_text: 2024-12-17T23:33:50.7402695Z # Escape the backtick as well so that we can have the settings in a code block on the GH issue 2024-12-17T23:33:50.7403595Z # for easy reading 2024-12-17T23:33:50.7404536Z # Note: Using ascii for the backtick so that the cat step in _runner-determinator.yml doesn't choke on 2024-12-17T23:33:50.7405566Z # the backtick character in shell commands. 2024-12-17T23:33:50.7406273Z backtick = chr(96) # backtick character 2024-12-17T23:33:50.7407074Z settings_text = settings_text.strip(f"\r\n\t{backtick} ") 2024-12-17T23:33:50.7408304Z settings = load_yaml(settings_text) 2024-12-17T23:33:50.7408866Z 2024-12-17T23:33:50.7409386Z # For now we just load experiments. We can expand this if/when we add more settings 2024-12-17T23:33:50.7410300Z experiments = {} 2024-12-17T23:33:50.7410695Z 2024-12-17T23:33:50.7411097Z for exp_name, exp_settings in settings.get(SETTING_EXPERIMENTS).items(): 2024-12-17T23:33:50.7411998Z if not is_valid_experiment_name(exp_name): 2024-12-17T23:33:50.7413293Z # 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:33:50.7414431Z continue 2024-12-17T23:33:50.7414809Z 2024-12-17T23:33:50.7415038Z valid_settings = {} 2024-12-17T23:33:50.7415735Z for setting in exp_settings: 2024-12-17T23:33:50.7416379Z if setting not in Experiment._fields: 2024-12-17T23:33:50.7417061Z log.warning( 2024-12-17T23:33:50.7417929Z f"Unexpected setting in experiment: {setting} = {exp_settings[setting]}" 2024-12-17T23:33:50.7418717Z ) 2024-12-17T23:33:50.7419264Z else: 2024-12-17T23:33:50.7419937Z valid_settings[setting] = exp_settings[setting] 2024-12-17T23:33:50.7420406Z 2024-12-17T23:33:50.7420730Z experiments[exp_name] = Experiment(**valid_settings) 2024-12-17T23:33:50.7421472Z return Settings(experiments) 2024-12-17T23:33:50.7421938Z 2024-12-17T23:33:50.7422166Z except Exception: 2024-12-17T23:33:50.7422754Z log.exception("Failed to parse settings") 2024-12-17T23:33:50.7423180Z 2024-12-17T23:33:50.7423549Z return Settings() 2024-12-17T23:33:50.7423967Z 2024-12-17T23:33:50.7423976Z 2024-12-17T23:33:50.7424305Z def parse_settings(rollout_state: str) -> Settings: 2024-12-17T23:33:50.7424994Z """ 2024-12-17T23:33:50.7425497Z Parse settings, if any, from the rollout state. 2024-12-17T23:33:50.7426050Z 2024-12-17T23:33:50.7426473Z If the issue body contains "---" then the text above that is the settings 2024-12-17T23:33:50.7427345Z and the text below is the list of opted in users. 2024-12-17T23:33:50.7427804Z 2024-12-17T23:33:50.7428255Z If it doesn't contain "---" then the settings are empty and the default values are used. 2024-12-17T23:33:50.7429187Z """ 2024-12-17T23:33:50.7429891Z settings_text, _ = extract_settings_user_opt_in_from_text(rollout_state) 2024-12-17T23:33:50.7430719Z return parse_settings_from_text(settings_text) 2024-12-17T23:33:50.7431261Z 2024-12-17T23:33:50.7431268Z 2024-12-17T23:33:50.7431579Z def parse_users(rollout_state: str) -> UserOptins: 2024-12-17T23:33:50.7432258Z """ 2024-12-17T23:33:50.7432735Z Parse users from the rollout state. 2024-12-17T23:33:50.7433207Z 2024-12-17T23:33:50.7433413Z """ 2024-12-17T23:33:50.7434047Z _, users_text = extract_settings_user_opt_in_from_text(rollout_state) 2024-12-17T23:33:50.7434890Z return parse_user_opt_in_from_text(users_text) 2024-12-17T23:33:50.7435401Z 2024-12-17T23:33:50.7435408Z 2024-12-17T23:33:50.7435888Z def is_user_opted_in(user: str, user_optins: UserOptins, experiment_name: str) -> bool: 2024-12-17T23:33:50.7436745Z """ 2024-12-17T23:33:50.7437269Z Check if a user is opted into an experiment 2024-12-17T23:33:50.7437967Z """ 2024-12-17T23:33:50.7438533Z return experiment_name in user_optins.get(user, []) 2024-12-17T23:33:50.7438986Z 2024-12-17T23:33:50.7439045Z 2024-12-17T23:33:50.7439484Z def is_user_opted_out(user: str, user_optins: UserOptins, experiment_name: str) -> bool: 2024-12-17T23:33:50.7440470Z """ 2024-12-17T23:33:50.7441017Z Check if a user explicitly opted out of an experiment 2024-12-17T23:33:50.7441711Z """ 2024-12-17T23:33:50.7442417Z # if the experiment is prefixed with a "-", then it's an opt-out 2024-12-17T23:33:50.7443387Z experiment_optout = "-" + experiment_name 2024-12-17T23:33:50.7444109Z if experiment_optout not in user_optins.get(user, []): 2024-12-17T23:33:50.7445043Z return False 2024-12-17T23:33:50.7445355Z 2024-12-17T23:33:50.7445666Z if is_user_opted_in(user, user_optins, experiment_name): 2024-12-17T23:33:50.7446366Z log.warning( 2024-12-17T23:33:50.7447384Z f"User {user} is opted into experiment {experiment_name}, but also opted out of it. Defaulting to opting out" 2024-12-17T23:33:50.7448961Z ) 2024-12-17T23:33:50.7449261Z 2024-12-17T23:33:50.7449458Z return True 2024-12-17T23:33:50.7449825Z 2024-12-17T23:33:50.7449832Z 2024-12-17T23:33:50.7450122Z def get_runner_prefix( 2024-12-17T23:33:50.7450644Z rollout_state: str, 2024-12-17T23:33:50.7451214Z workflow_requestors: Iterable[str], 2024-12-17T23:33:50.7451945Z branch: str, 2024-12-17T23:33:50.7452511Z eligible_experiments: FrozenSet[str] = frozenset(), 2024-12-17T23:33:50.7453216Z is_canary: bool = False, 2024-12-17T23:33:50.7453873Z ) -> str: 2024-12-17T23:33:50.7454363Z settings = parse_settings(rollout_state) 2024-12-17T23:33:50.7455030Z user_optins = parse_users(rollout_state) 2024-12-17T23:33:50.7455588Z 2024-12-17T23:33:50.7455803Z fleet_prefix = "" 2024-12-17T23:33:50.7456301Z prefixes = [] 2024-12-17T23:33:50.7457034Z for experiment_name, experiment_settings in settings.experiments.items(): 2024-12-17T23:33:50.7458186Z if not experiment_settings.all_branches and is_exception_branch(branch): 2024-12-17T23:33:50.7459005Z log.info( 2024-12-17T23:33:50.7459745Z f"Branch {branch} is an exception branch. Not enabling experiment {experiment_name}." 2024-12-17T23:33:50.7460699Z ) 2024-12-17T23:33:50.7461358Z continue 2024-12-17T23:33:50.7461694Z 2024-12-17T23:33:50.7461912Z if eligible_experiments: 2024-12-17T23:33:50.7462676Z if experiment_name not in eligible_experiments: 2024-12-17T23:33:50.7463444Z exp_list = ", ".join(eligible_experiments) 2024-12-17T23:33:50.7464063Z log.info( 2024-12-17T23:33:50.7465049Z f"Skipping experiment '{experiment_name}', as it is not in the eligible_experiments list: {exp_list}" 2024-12-17T23:33:50.7466015Z ) 2024-12-17T23:33:50.7466465Z continue 2024-12-17T23:33:50.7467126Z elif not experiment_settings.default: 2024-12-17T23:33:50.7467799Z log.info( 2024-12-17T23:33:50.7468515Z f"Skipping experiment '{experiment_name}', as it is not a default experiment" 2024-12-17T23:33:50.7469443Z ) 2024-12-17T23:33:50.7469945Z continue 2024-12-17T23:33:50.7470228Z 2024-12-17T23:33:50.7470533Z # Is any workflow_requestor opted out to this experiment? 2024-12-17T23:33:50.7471351Z opted_out_users = [ 2024-12-17T23:33:50.7471921Z requestor 2024-12-17T23:33:50.7472443Z for requestor in workflow_requestors 2024-12-17T23:33:50.7473315Z if is_user_opted_out(requestor, user_optins, experiment_name) 2024-12-17T23:33:50.7474071Z ] 2024-12-17T23:33:50.7474314Z 2024-12-17T23:33:50.7474517Z if opted_out_users: 2024-12-17T23:33:50.7475183Z log.info( 2024-12-17T23:33:50.7475908Z f"{', '.join(opted_out_users)} have opted out of experiment {experiment_name}." 2024-12-17T23:33:50.7476762Z ) 2024-12-17T23:33:50.7477243Z continue 2024-12-17T23:33:50.7477564Z 2024-12-17T23:33:50.7477867Z # Is any workflow_requestor opted in to this experiment? 2024-12-17T23:33:50.7478631Z opted_in_users = [ 2024-12-17T23:33:50.7479178Z requestor 2024-12-17T23:33:50.7479739Z for requestor in workflow_requestors 2024-12-17T23:33:50.7480562Z if is_user_opted_in(requestor, user_optins, experiment_name) 2024-12-17T23:33:50.7481293Z ] 2024-12-17T23:33:50.7481568Z 2024-12-17T23:33:50.7481945Z enabled = False 2024-12-17T23:33:50.7482577Z if opted_in_users: 2024-12-17T23:33:50.7483126Z log.info( 2024-12-17T23:33:50.7483842Z f"{', '.join(opted_in_users)} have opted into experiment {experiment_name}." 2024-12-17T23:33:50.7484701Z ) 2024-12-17T23:33:50.7485185Z enabled = True 2024-12-17T23:33:50.7485541Z 2024-12-17T23:33:50.7485792Z elif experiment_settings.rollout_perc: 2024-12-17T23:33:50.7486782Z # If no user is opted in, then we randomly enable the experiment based on the rollout percentage 2024-12-17T23:33:50.7487810Z if random.uniform(0, 100) <= experiment_settings.rollout_perc: 2024-12-17T23:33:50.7488986Z log.info( 2024-12-17T23:33:50.7490081Z f"Based on rollout percentage of {experiment_settings.rollout_perc}%, enabling experiment {experiment_name}." 2024-12-17T23:33:50.7491111Z ) 2024-12-17T23:33:50.7491641Z enabled = True 2024-12-17T23:33:50.7492164Z 2024-12-17T23:33:50.7492372Z if enabled: 2024-12-17T23:33:50.7492868Z label = experiment_name 2024-12-17T23:33:50.7493526Z if experiment_name == LF_FLEET_EXPERIMENT: 2024-12-17T23:33:50.7494535Z # We give some special treatment to the "lf" experiment since determines the fleet we use 2024-12-17T23:33:50.7495533Z # - If it's enabled, then we always list it's prefix first 2024-12-17T23:33:50.7496344Z # - If we're in the canary branch, then we append ".c" to the lf prefix 2024-12-17T23:33:50.7497204Z if is_canary: 2024-12-17T23:33:50.7497831Z label += CANARY_FLEET_SUFFIX 2024-12-17T23:33:50.7498438Z fleet_prefix = label 2024-12-17T23:33:50.7499310Z else: 2024-12-17T23:33:50.7499874Z prefixes.append(label) 2024-12-17T23:33:50.7500263Z 2024-12-17T23:33:50.7500465Z if len(prefixes) > 1: 2024-12-17T23:33:50.7501138Z log.error( 2024-12-17T23:33:50.7502289Z 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:33:50.7503502Z ) 2024-12-17T23:33:50.7504101Z prefixes = prefixes[:1] 2024-12-17T23:33:50.7504455Z 2024-12-17T23:33:50.7504712Z # Fleet always comes first 2024-12-17T23:33:50.7505340Z if fleet_prefix: 2024-12-17T23:33:50.7505898Z prefixes.insert(0, fleet_prefix) 2024-12-17T23:33:50.7506341Z 2024-12-17T23:33:50.7506626Z return ".".join(prefixes) + "." if prefixes else "" 2024-12-17T23:33:50.7507079Z 2024-12-17T23:33:50.7507086Z 2024-12-17T23:33:50.7507644Z def get_rollout_state_from_issue(github_token: str, repo: str, issue_num: int) -> str: 2024-12-17T23:33:50.7508535Z """ 2024-12-17T23:33:50.7509228Z Gets the first comment of the issue, which contains the desired rollout state. 2024-12-17T23:33:50.7509830Z 2024-12-17T23:33:50.7510365Z The default issue we use - https://github.com/pytorch/test-infra/issues/5132 2024-12-17T23:33:50.7511182Z """ 2024-12-17T23:33:50.7511679Z gh = get_gh_client(github_token) 2024-12-17T23:33:50.7512394Z issue = get_issue(gh, repo, issue_num) 2024-12-17T23:33:50.7513133Z return str(issue.get_comments()[0].body.strip("\n\t ")) 2024-12-17T23:33:50.7513653Z 2024-12-17T23:33:50.7513660Z 2024-12-17T23:33:50.7514097Z def download_json(url: str, headers: Dict[str, str], num_retries: int = 3) -> Any: 2024-12-17T23:33:50.7515040Z for _ in range(num_retries): 2024-12-17T23:33:50.7515655Z try: 2024-12-17T23:33:50.7516154Z req = Request(url=url, headers=headers) 2024-12-17T23:33:50.7516986Z content = urlopen(req, timeout=5).read().decode("utf-8") 2024-12-17T23:33:50.7517761Z return json.loads(content) 2024-12-17T23:33:50.7518359Z except Exception as e: 2024-12-17T23:33:50.7519074Z log.warning(f"Could not download {url}: {e}") 2024-12-17T23:33:50.7519720Z 2024-12-17T23:33:50.7520181Z log.warning(f"All {num_retries} retries exhausted, downloading {url} failed") 2024-12-17T23:33:50.7520987Z return {} 2024-12-17T23:33:50.7521270Z 2024-12-17T23:33:50.7521276Z 2024-12-17T23:33:50.7521562Z @lru_cache(maxsize=None) 2024-12-17T23:33:50.7522391Z def get_pr_info(github_repo: str, github_token: str, pr_number: int) -> Dict[str, Any]: 2024-12-17T23:33:50.7523243Z """ 2024-12-17T23:33:50.7523796Z Dynamically get PR information 2024-12-17T23:33:50.7524438Z """ 2024-12-17T23:33:50.7525002Z github_api = f"https://api.github.com/repos/{github_repo}" 2024-12-17T23:33:50.7525789Z headers = { 2024-12-17T23:33:50.7526381Z "Accept": "application/vnd.github.v3+json", 2024-12-17T23:33:50.7527058Z "Authorization": f"token {github_token}", 2024-12-17T23:33:50.7527745Z } 2024-12-17T23:33:50.7528860Z json_response: Dict[str, Any] = download_json( 2024-12-17T23:33:50.7529572Z url=f"{github_api}/issues/{pr_number}", 2024-12-17T23:33:50.7530315Z headers=headers, 2024-12-17T23:33:50.7530886Z ) 2024-12-17T23:33:50.7531130Z 2024-12-17T23:33:50.7531348Z if not json_response: 2024-12-17T23:33:50.7532076Z log.warning(f"Failed to get the labels for #{pr_number}") 2024-12-17T23:33:50.7532856Z return {} 2024-12-17T23:33:50.7533132Z 2024-12-17T23:33:50.7533347Z return json_response 2024-12-17T23:33:50.7533692Z 2024-12-17T23:33:50.7533700Z 2024-12-17T23:33:50.7534202Z def get_labels(github_repo: str, github_token: str, pr_number: int) -> Set[str]: 2024-12-17T23:33:50.7535084Z """ 2024-12-17T23:33:50.7535719Z Dynamically get the latest list of labels from the pull request 2024-12-17T23:33:50.7536492Z """ 2024-12-17T23:33:50.7537283Z pr_info = get_pr_info(github_repo, github_token, pr_number) 2024-12-17T23:33:50.7538032Z return { 2024-12-17T23:33:50.7538771Z label.get("name") for label in pr_info.get("labels", []) if label.get("name") 2024-12-17T23:33:50.7539620Z } 2024-12-17T23:33:50.7539860Z 2024-12-17T23:33:50.7539868Z 2024-12-17T23:33:50.7540167Z def main() -> None: 2024-12-17T23:33:50.7540741Z args = parse_args() 2024-12-17T23:33:50.7541116Z 2024-12-17T23:33:50.7541377Z runner_label_prefix = DEFAULT_LABEL_PREFIX 2024-12-17T23:33:50.7541804Z 2024-12-17T23:33:50.7542079Z # Check if the PR is opt-out 2024-12-17T23:33:50.7542690Z if args.pr_number: 2024-12-17T23:33:50.7543469Z labels = get_labels(args.github_repo, args.github_token, int(args.pr_number)) 2024-12-17T23:33:50.7544339Z if OPT_OUT_LABEL in labels: 2024-12-17T23:33:50.7544955Z log.info( 2024-12-17T23:33:50.7545764Z f"Opt-out runner determinator because #{args.pr_number} has {OPT_OUT_LABEL} label" 2024-12-17T23:33:50.7546654Z ) 2024-12-17T23:33:50.7547365Z set_github_output(GH_OUTPUT_KEY_LABEL_TYPE, runner_label_prefix) 2024-12-17T23:33:50.7548108Z sys.exit() 2024-12-17T23:33:50.7548462Z 2024-12-17T23:33:50.7548673Z try: 2024-12-17T23:33:50.7549279Z rollout_state = get_rollout_state_from_issue( 2024-12-17T23:33:50.7550065Z args.github_token, args.github_issue_repo, args.github_issue 2024-12-17T23:33:50.7550820Z ) 2024-12-17T23:33:50.7551050Z 2024-12-17T23:33:50.7551404Z username = get_potential_pr_author( 2024-12-17T23:33:50.7552040Z args.github_token, 2024-12-17T23:33:50.7552620Z args.github_repo, 2024-12-17T23:33:50.7553266Z args.github_actor, 2024-12-17T23:33:50.7553832Z args.github_ref_type, 2024-12-17T23:33:50.7554433Z args.github_branch, 2024-12-17T23:33:50.7555048Z ) 2024-12-17T23:33:50.7555311Z 2024-12-17T23:33:50.7555637Z is_canary = args.github_repo == "pytorch/pytorch-canary" 2024-12-17T23:33:50.7556170Z 2024-12-17T23:33:50.7556430Z runner_label_prefix = get_runner_prefix( 2024-12-17T23:33:50.7557150Z rollout_state, 2024-12-17T23:33:50.7557914Z (args.github_issue_owner, username), 2024-12-17T23:33:50.7558568Z args.github_branch, 2024-12-17T23:33:50.7559258Z args.eligible_experiments, 2024-12-17T23:33:50.7559846Z is_canary, 2024-12-17T23:33:50.7560358Z ) 2024-12-17T23:33:50.7560589Z 2024-12-17T23:33:50.7560945Z except Exception as e: 2024-12-17T23:33:50.7561470Z log.error( 2024-12-17T23:33:50.7562242Z f"Failed to get issue. Defaulting to Meta runners and no experiments. Exception: {e}" 2024-12-17T23:33:50.7563199Z ) 2024-12-17T23:33:50.7563446Z 2024-12-17T23:33:50.7563809Z set_github_output(GH_OUTPUT_KEY_LABEL_TYPE, runner_label_prefix) 2024-12-17T23:33:50.7564399Z 2024-12-17T23:33:50.7564405Z 2024-12-17T23:33:50.7564619Z if __name__ == "__main__": 2024-12-17T23:33:50.7565256Z main() 2024-12-17T23:33:50.7565506Z 2024-12-17T23:33:50.7656123Z ##[group]Run python3 -m pip install urllib3==1.26.18 PyGithub==2.3.0 2024-12-17T23:33:50.7657206Z python3 -m pip install urllib3==1.26.18 PyGithub==2.3.0 2024-12-17T23:33:50.7710630Z shell: /usr/bin/bash -e {0} 2024-12-17T23:33:50.7711259Z env: 2024-12-17T23:33:50.7711936Z GITHUB_TOKEN: *** 2024-12-17T23:33:50.7712545Z ISSUE_NUMBER: 5132 2024-12-17T23:33:50.7713103Z TRIGGERING_ACTOR: malfet 2024-12-17T23:33:50.7713641Z ISSUE_OWNER: 2024-12-17T23:33:50.7714194Z CHECK_EXPERIMENTS: 2024-12-17T23:33:50.7714737Z PR_NUMBER: 2024-12-17T23:33:50.7715190Z ##[endgroup] 2024-12-17T23:33:51.1659656Z Defaulting to user installation because normal site-packages is not writeable 2024-12-17T23:33:51.5048422Z Collecting urllib3==1.26.18 2024-12-17T23:33:51.5750519Z Downloading urllib3-1.26.18-py2.py3-none-any.whl (143 kB) 2024-12-17T23:33:51.6130474Z ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 143.8/143.8 KB 5.2 MB/s eta 0:00:00 2024-12-17T23:33:51.6413701Z Collecting PyGithub==2.3.0 2024-12-17T23:33:51.6546223Z Downloading PyGithub-2.3.0-py3-none-any.whl (354 kB) 2024-12-17T23:33:51.6721793Z ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 354.4/354.4 KB 22.0 MB/s eta 0:00:00 2024-12-17T23:33:51.7290331Z Collecting pynacl>=1.4.0 2024-12-17T23:33:51.7419575Z 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:33:51.7619908Z ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 856.7/856.7 KB 46.9 MB/s eta 0:00:00 2024-12-17T23:33:51.7938574Z Collecting typing-extensions>=4.0.0 2024-12-17T23:33:51.8064577Z Downloading typing_extensions-4.12.2-py3-none-any.whl (37 kB) 2024-12-17T23:33:51.8458316Z Collecting pyjwt[crypto]>=2.4.0 2024-12-17T23:33:51.8586312Z Downloading PyJWT-2.10.1-py3-none-any.whl (22 kB) 2024-12-17T23:33:51.8870321Z Collecting Deprecated 2024-12-17T23:33:51.8996105Z Downloading Deprecated-1.2.15-py2.py3-none-any.whl (9.9 kB) 2024-12-17T23:33:51.9068242Z Requirement already satisfied: requests>=2.14.0 in /usr/lib/python3/dist-packages (from PyGithub==2.3.0) (2.25.1) 2024-12-17T23:33:51.9179922Z 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:33:52.1472943Z Collecting cffi>=1.4.1 2024-12-17T23:33:52.1601640Z Downloading cffi-1.17.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (446 kB) 2024-12-17T23:33:52.1672603Z ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 446.2/446.2 KB 86.1 MB/s eta 0:00:00 2024-12-17T23:33:52.3611888Z Collecting wrapt<2,>=1.10 2024-12-17T23:33:52.3744776Z 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:33:52.3805978Z ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 82.7/82.7 KB 20.9 MB/s eta 0:00:00 2024-12-17T23:33:52.4227114Z Collecting pycparser 2024-12-17T23:33:52.4363638Z Downloading pycparser-2.22-py3-none-any.whl (117 kB) 2024-12-17T23:33:52.4429470Z ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 117.6/117.6 KB 31.6 MB/s eta 0:00:00 2024-12-17T23:33:52.6429973Z Installing collected packages: wrapt, urllib3, typing-extensions, pyjwt, pycparser, Deprecated, cffi, pynacl, PyGithub 2024-12-17T23:33:53.1117166Z 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:33:53.1849672Z ##[group]Run curr_branch="release/2.6" 2024-12-17T23:33:53.1850294Z curr_branch="release/2.6" 2024-12-17T23:33:53.1850711Z curr_ref_type="branch" 2024-12-17T23:33:53.1851135Z echo "Current branch is '$curr_branch'" 2024-12-17T23:33:53.1851589Z  2024-12-17T23:33:53.1851950Z python3 runner_determinator.py \ 2024-12-17T23:33:53.1852369Z  --github-token "$GITHUB_TOKEN" \ 2024-12-17T23:33:53.1852794Z  --github-issue "$ISSUE_NUMBER" \ 2024-12-17T23:33:53.1853244Z  --github-branch "$curr_branch" \ 2024-12-17T23:33:53.1853666Z  --github-actor "$TRIGGERING_ACTOR" \ 2024-12-17T23:33:53.1854121Z  --github-issue-owner "$ISSUE_OWNER" \ 2024-12-17T23:33:53.1854606Z  --github-ref-type "$curr_ref_type" \ 2024-12-17T23:33:53.1855027Z  --github-repo "$GITHUB_REPOSITORY" \ 2024-12-17T23:33:53.1855492Z  --eligible-experiments "$CHECK_EXPERIMENTS" \ 2024-12-17T23:33:53.1856065Z  --pr-number "${PR_NUMBER}" 2024-12-17T23:33:53.1915376Z shell: /usr/bin/bash -e {0} 2024-12-17T23:33:53.1915759Z env: 2024-12-17T23:33:53.1916595Z GITHUB_TOKEN: *** 2024-12-17T23:33:53.1916998Z ISSUE_NUMBER: 5132 2024-12-17T23:33:53.1917388Z TRIGGERING_ACTOR: malfet 2024-12-17T23:33:53.1917788Z ISSUE_OWNER: 2024-12-17T23:33:53.1918125Z CHECK_EXPERIMENTS: 2024-12-17T23:33:53.1918449Z PR_NUMBER: 2024-12-17T23:33:53.1918784Z ##[endgroup] 2024-12-17T23:33:53.1996722Z Current branch is 'release/2.6' 2024-12-17T23:33:54.4776013Z INFO : Based on rollout percentage of 95%, enabling experiment lf. 2024-12-17T23:33:54.4777494Z INFO : Skipping experiment 'awsa100', as it is not a default experiment 2024-12-17T23:33:54.4778506Z INFO : Setting output: label-type='lf.' 2024-12-17T23:33:54.5059289Z Evaluate and set job outputs 2024-12-17T23:33:54.5066431Z Set output 'label-type' 2024-12-17T23:33:54.5068432Z Cleaning up orphan processes