2024-12-17T23:28:37.3573685Z Current runner version: '2.321.0' 2024-12-17T23:28:37.3599343Z ##[group]Operating System 2024-12-17T23:28:37.3600185Z Ubuntu 2024-12-17T23:28:37.3600682Z 22.04.5 2024-12-17T23:28:37.3601172Z LTS 2024-12-17T23:28:37.3601710Z ##[endgroup] 2024-12-17T23:28:37.3602241Z ##[group]Runner Image 2024-12-17T23:28:37.3602785Z Image: ubuntu-22.04 2024-12-17T23:28:37.3603331Z Version: 20241211.1.0 2024-12-17T23:28:37.3604342Z Included Software: https://github.com/actions/runner-images/blob/ubuntu22/20241211.1/images/ubuntu/Ubuntu2204-Readme.md 2024-12-17T23:28:37.3605650Z Image Release: https://github.com/actions/runner-images/releases/tag/ubuntu22%2F20241211.1 2024-12-17T23:28:37.3606572Z ##[endgroup] 2024-12-17T23:28:37.3607094Z ##[group]Runner Image Provisioner 2024-12-17T23:28:37.3607655Z 2.0.404.1 2024-12-17T23:28:37.3608157Z ##[endgroup] 2024-12-17T23:28:37.3610207Z ##[group]GITHUB_TOKEN Permissions 2024-12-17T23:28:37.3612408Z Actions: read 2024-12-17T23:28:37.3613098Z Attestations: read 2024-12-17T23:28:37.3613751Z Checks: read 2024-12-17T23:28:37.3614227Z Contents: read 2024-12-17T23:28:37.3614719Z Deployments: read 2024-12-17T23:28:37.3615263Z Discussions: read 2024-12-17T23:28:37.3615754Z Issues: read 2024-12-17T23:28:37.3616232Z Metadata: read 2024-12-17T23:28:37.3616768Z Packages: read 2024-12-17T23:28:37.3617256Z Pages: read 2024-12-17T23:28:37.3617738Z PullRequests: read 2024-12-17T23:28:37.3618306Z RepositoryProjects: read 2024-12-17T23:28:37.3618871Z SecurityEvents: read 2024-12-17T23:28:37.3619366Z Statuses: read 2024-12-17T23:28:37.3619885Z ##[endgroup] 2024-12-17T23:28:37.3622780Z Secret source: Actions 2024-12-17T23:28:37.3623448Z Prepare workflow directory 2024-12-17T23:28:37.4097692Z Prepare all required actions 2024-12-17T23:28:37.4151524Z Uses: pytorch/pytorch/.github/workflows/_runner-determinator.yml@refs/heads/release/2.6 (0cdf8b1d09254cfda66191d1bd01e3041c3c76f7) 2024-12-17T23:28:37.4156573Z ##[group] Inputs 2024-12-17T23:28:37.4157196Z check_experiments: 2024-12-17T23:28:37.4157733Z triggering_actor: malfet 2024-12-17T23:28:37.4158419Z issue_owner: 2024-12-17T23:28:37.4159005Z curr_branch: release/2.6 2024-12-17T23:28:37.4159579Z curr_ref_type: branch 2024-12-17T23:28:37.4160183Z issue_number: 5132 2024-12-17T23:28:37.4160715Z ##[endgroup] 2024-12-17T23:28:37.4161249Z Complete job name: get-label-type / runner-determinator 2024-12-17T23:28:37.4785556Z ##[group]Run cat < runner_determinator.py 2024-12-17T23:28:37.4787882Z cat < runner_determinator.py 2024-12-17T23:28:37.4788559Z # flake8: noqa: G004 2024-12-17T23:28:37.4789084Z  2024-12-17T23:28:37.4789873Z # Note: Copies of this script in runner_determinator.py and _runner-determinator.yml 2024-12-17T23:28:37.4790938Z # must be kept in sync. You can do it easily by running the following command: 2024-12-17T23:28:37.4791838Z # python .github/scripts/update_runner_determinator.py 2024-12-17T23:28:37.4792593Z  2024-12-17T23:28:37.4793098Z """ 2024-12-17T23:28:37.4793759Z This runner determinator is used to determine which set of runners to run a 2024-12-17T23:28:37.4794793Z GitHub job on. It uses the first comment of a GitHub issue (by default 2024-12-17T23:28:37.4795933Z https://github.com/pytorch/test-infra/issues/5132) to define the configuration 2024-12-17T23:28:37.4796816Z of which runners should be used to run which job. 2024-12-17T23:28:37.4797576Z  2024-12-17T23:28:37.4798255Z The configuration has two parts, the settings and a list of opted-in users, 2024-12-17T23:28:37.4799206Z separated by a line containing "---". If the line is not present, the 2024-12-17T23:28:37.4800286Z settings are considered to be empty with only the second part, the user 2024-12-17T23:28:37.4801093Z list, defined. 2024-12-17T23:28:37.4801658Z  2024-12-17T23:28:37.4802312Z The first part is a YAML block that defines the rollout settings. This can be 2024-12-17T23:28:37.4803807Z used to define any settings that are needed to determine which runners to use. 2024-12-17T23:28:37.4804852Z It's fields are defined by the RolloutSettings class below. 2024-12-17T23:28:37.4805529Z  2024-12-17T23:28:37.4806200Z The second part is a list of users who are explicitly opted in to the LF fleet. 2024-12-17T23:28:37.4807245Z The user list is also a comma separated list of additional features or 2024-12-17T23:28:37.4808087Z experiments which the user could be opted in to. 2024-12-17T23:28:37.4808737Z  2024-12-17T23:28:37.4809294Z The user list has the following rules: 2024-12-17T23:28:37.4809934Z  2024-12-17T23:28:37.4810510Z - Users are GitHub usernames, which must start with the @ prefix 2024-12-17T23:28:37.4811517Z - Each user is also a comma-separated list of features/experiments to enable 2024-12-17T23:28:37.4812403Z - A "#" prefix opts the user out of all experiments 2024-12-17T23:28:37.4813020Z  2024-12-17T23:28:37.4813550Z Example config: 2024-12-17T23:28:37.4814179Z  # A list of experiments that can be opted into. 2024-12-17T23:28:37.4814954Z  # This defines the behavior they'll induce when opted into. 2024-12-17T23:28:37.4815745Z  # Expected syntax is: 2024-12-17T23:28:37.4816567Z  # [experiment_name]: # Name of the experiment. Also used for the label prefix. 2024-12-17T23:28:37.4817662Z  # rollout_perc: [int] # % of workflows to run with this experiment when users are not opted in. 2024-12-17T23:28:37.4818533Z  2024-12-17T23:28:37.4819027Z  experiments: 2024-12-17T23:28:37.4819567Z  lf: 2024-12-17T23:28:37.4820081Z  rollout_percent: 25 2024-12-17T23:28:37.4820692Z  all_branches: false 2024-12-17T23:28:37.4821286Z  default: true 2024-12-17T23:28:37.4821845Z  --- 2024-12-17T23:28:37.4822344Z  2024-12-17T23:28:37.4822791Z  # Opt-ins: 2024-12-17T23:28:37.4823534Z  # Users can opt into the LF fleet by adding their GitHub username to this list 2024-12-17T23:28:37.4824722Z  # and specifying experiments to enable in a comma-separated list. 2024-12-17T23:28:37.4825963Z  # To always opt out of an experiment, prefix it with a "-". 2024-12-17T23:28:37.4826790Z  # Experiments should be from the above list. 2024-12-17T23:28:37.4827484Z  2024-12-17T23:28:37.4827999Z  @User1,-lf,split_build 2024-12-17T23:28:37.4828660Z  @User2,lf 2024-12-17T23:28:37.4829153Z  @User3,split_build 2024-12-17T23:28:37.4829695Z """ 2024-12-17T23:28:37.4830220Z  2024-12-17T23:28:37.4830639Z import json 2024-12-17T23:28:37.4831147Z import logging 2024-12-17T23:28:37.4831733Z import os 2024-12-17T23:28:37.4832202Z import random 2024-12-17T23:28:37.4832710Z import re 2024-12-17T23:28:37.4833292Z import sys 2024-12-17T23:28:37.4833793Z from argparse import ArgumentParser 2024-12-17T23:28:37.4834429Z from functools import lru_cache 2024-12-17T23:28:37.4835129Z from logging import LogRecord 2024-12-17T23:28:37.4835941Z from typing import Any, Dict, FrozenSet, Iterable, List, NamedTuple, Set, Tuple 2024-12-17T23:28:37.4836854Z from urllib.request import Request, urlopen 2024-12-17T23:28:37.4837547Z  2024-12-17T23:28:37.4837963Z import yaml 2024-12-17T23:28:37.4838502Z from github import Auth, Github 2024-12-17T23:28:37.4839172Z from github.Issue import Issue 2024-12-17T23:28:37.4839741Z  2024-12-17T23:28:37.4840150Z  2024-12-17T23:28:37.4840744Z DEFAULT_LABEL_PREFIX = "" # use meta runners 2024-12-17T23:28:37.4841784Z WORKFLOW_LABEL_LF = "lf." # use runners from the linux foundation 2024-12-17T23:28:37.4842722Z WORKFLOW_LABEL_LF_CANARY = "lf.c." # use canary runners from the linux foundation 2024-12-17T23:28:37.4843594Z  2024-12-17T23:28:37.4844146Z GITHUB_OUTPUT = os.getenv("GITHUB_OUTPUT", "") 2024-12-17T23:28:37.4844802Z GH_OUTPUT_KEY_AMI = "runner-ami" 2024-12-17T23:28:37.4845518Z GH_OUTPUT_KEY_LABEL_TYPE = "label-type" 2024-12-17T23:28:37.4846219Z OPT_OUT_LABEL = "no-runner-experiments" 2024-12-17T23:28:37.4846806Z  2024-12-17T23:28:37.4847357Z SETTING_EXPERIMENTS = "experiments" 2024-12-17T23:28:37.4847977Z  2024-12-17T23:28:37.4848397Z LF_FLEET_EXPERIMENT = "lf" 2024-12-17T23:28:37.4849062Z CANARY_FLEET_SUFFIX = ".c" 2024-12-17T23:28:37.4849641Z  2024-12-17T23:28:37.4850035Z  2024-12-17T23:28:37.4850585Z class Experiment(NamedTuple): 2024-12-17T23:28:37.4851203Z  rollout_perc: float = ( 2024-12-17T23:28:37.4851953Z  0 # Percentage of workflows to experiment on when user is not opted-in. 2024-12-17T23:28:37.4852807Z  ) 2024-12-17T23:28:37.4853302Z  all_branches: bool = ( 2024-12-17T23:28:37.4854040Z  False # If True, the experiment is also enabled on the exception branches 2024-12-17T23:28:37.4854889Z  ) 2024-12-17T23:28:37.4855367Z  default: bool = ( 2024-12-17T23:28:37.4856074Z  True # If True, the experiment is enabled by default for all queries 2024-12-17T23:28:37.4856879Z  ) 2024-12-17T23:28:37.4857336Z  2024-12-17T23:28:37.4857789Z  # Add more fields as needed 2024-12-17T23:28:37.4858416Z  2024-12-17T23:28:37.4858850Z  2024-12-17T23:28:37.4859313Z class Settings(NamedTuple): 2024-12-17T23:28:37.4859919Z  """ 2024-12-17T23:28:37.4860509Z  Settings for the experiments that can be opted into. 2024-12-17T23:28:37.4861195Z  """ 2024-12-17T23:28:37.4861699Z  2024-12-17T23:28:37.4862206Z  experiments: Dict[str, Experiment] = {} 2024-12-17T23:28:37.4862837Z  2024-12-17T23:28:37.4863309Z  2024-12-17T23:28:37.4863991Z class ColorFormatter(logging.Formatter): 2024-12-17T23:28:37.4864730Z  """Color codes the log messages based on the log level""" 2024-12-17T23:28:37.4866084Z  2024-12-17T23:28:37.4866563Z  COLORS = { 2024-12-17T23:28:37.4867122Z  "WARNING": "\033[33m", # Yellow 2024-12-17T23:28:37.4867797Z  "ERROR": "\033[31m", # Red 2024-12-17T23:28:37.4868454Z  "CRITICAL": "\033[31m", # Red 2024-12-17T23:28:37.4869075Z  "INFO": "\033[0m", # Reset 2024-12-17T23:28:37.4869742Z  "DEBUG": "\033[0m", # Reset 2024-12-17T23:28:37.4870361Z  } 2024-12-17T23:28:37.4870833Z  2024-12-17T23:28:37.4871401Z  def format(self, record: LogRecord) -> str: 2024-12-17T23:28:37.4872289Z  log_color = self.COLORS.get(record.levelname, "\033[0m") # Default to reset 2024-12-17T23:28:37.4873152Z  record.msg = f"{log_color}{record.msg}\033[0m" 2024-12-17T23:28:37.4873920Z  return super().format(record) 2024-12-17T23:28:37.4874498Z  2024-12-17T23:28:37.4874922Z  2024-12-17T23:28:37.4875488Z handler = logging.StreamHandler() 2024-12-17T23:28:37.4876316Z handler.setFormatter(ColorFormatter(fmt="%(levelname)-8s: %(message)s")) 2024-12-17T23:28:37.4877113Z  2024-12-17T23:28:37.4877745Z log = logging.getLogger(os.path.basename(__file__)) 2024-12-17T23:28:37.4878434Z log.addHandler(handler) 2024-12-17T23:28:37.4879005Z log.setLevel(logging.INFO) 2024-12-17T23:28:37.4879658Z  2024-12-17T23:28:37.4880249Z  2024-12-17T23:28:37.4880806Z def set_github_output(key: str, value: str) -> None: 2024-12-17T23:28:37.4881584Z  """ 2024-12-17T23:28:37.4882185Z  Defines outputs of the github action that invokes this script 2024-12-17T23:28:37.4882891Z  """ 2024-12-17T23:28:37.4883481Z  if not GITHUB_OUTPUT: 2024-12-17T23:28:37.4884643Z  # 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.4885816Z  log.warning( 2024-12-17T23:28:37.4886908Z  "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.4887909Z  ) 2024-12-17T23:28:37.4888412Z  print(f"::set-output name={key}::{value}") 2024-12-17T23:28:37.4889146Z  return 2024-12-17T23:28:37.4889657Z  2024-12-17T23:28:37.4890119Z  with open(GITHUB_OUTPUT, "a") as f: 2024-12-17T23:28:37.4890894Z  log.info(f"Setting output: {key}='{value}'") 2024-12-17T23:28:37.4891576Z  f.write(f"{key}={value}\n") 2024-12-17T23:28:37.4892130Z  2024-12-17T23:28:37.4892663Z  2024-12-17T23:28:37.4893274Z def _str_comma_separated_to_set(value: str) -> FrozenSet[str]: 2024-12-17T23:28:37.4893986Z  return frozenset( 2024-12-17T23:28:37.4894822Z  filter(lambda itm: itm != "", map(str.strip, value.strip(" \n\t").split(","))) 2024-12-17T23:28:37.4895605Z  ) 2024-12-17T23:28:37.4896113Z  2024-12-17T23:28:37.4896522Z  2024-12-17T23:28:37.4896991Z def parse_args() -> Any: 2024-12-17T23:28:37.4897733Z  parser = ArgumentParser("Get dynamic rollout settings") 2024-12-17T23:28:37.4898677Z  parser.add_argument("--github-token", type=str, required=True, help="GitHub token") 2024-12-17T23:28:37.4899561Z  parser.add_argument( 2024-12-17T23:28:37.4900192Z  "--github-issue-repo", 2024-12-17T23:28:37.4900760Z  type=str, 2024-12-17T23:28:37.4901309Z  required=False, 2024-12-17T23:28:37.4902127Z  default="pytorch/test-infra", 2024-12-17T23:28:37.4902810Z  help="GitHub repo to get the issue", 2024-12-17T23:28:37.4903428Z  ) 2024-12-17T23:28:37.4903962Z  parser.add_argument( 2024-12-17T23:28:37.4904529Z  "--github-repo", 2024-12-17T23:28:37.4905083Z  type=str, 2024-12-17T23:28:37.4906069Z  required=True, 2024-12-17T23:28:37.4906688Z  help="GitHub repo where CI is running", 2024-12-17T23:28:37.4907308Z  ) 2024-12-17T23:28:37.4907838Z  parser.add_argument( 2024-12-17T23:28:37.4908582Z  "--github-issue", type=int, required=True, help="GitHub issue number" 2024-12-17T23:28:37.4909352Z  ) 2024-12-17T23:28:37.4909885Z  parser.add_argument( 2024-12-17T23:28:37.4910683Z  "--github-actor", type=str, required=True, help="GitHub triggering_actor" 2024-12-17T23:28:37.4911463Z  ) 2024-12-17T23:28:37.4911976Z  parser.add_argument( 2024-12-17T23:28:37.4912767Z  "--github-issue-owner", type=str, required=True, help="GitHub issue owner" 2024-12-17T23:28:37.4913554Z  ) 2024-12-17T23:28:37.4914107Z  parser.add_argument( 2024-12-17T23:28:37.4914860Z  "--github-branch", type=str, required=True, help="Current GitHub branch or tag" 2024-12-17T23:28:37.4915651Z  ) 2024-12-17T23:28:37.4916208Z  parser.add_argument( 2024-12-17T23:28:37.4916751Z  "--github-ref-type", 2024-12-17T23:28:37.4917334Z  type=str, 2024-12-17T23:28:37.4918151Z  required=True, 2024-12-17T23:28:37.4918745Z  help="Current GitHub ref type, branch or tag", 2024-12-17T23:28:37.4919400Z  ) 2024-12-17T23:28:37.4919936Z  parser.add_argument( 2024-12-17T23:28:37.4920485Z  "--eligible-experiments", 2024-12-17T23:28:37.4921146Z  type=_str_comma_separated_to_set, 2024-12-17T23:28:37.4921832Z  required=False, 2024-12-17T23:28:37.4922353Z  default="", 2024-12-17T23:28:37.4923351Z  help="comma separated list of experiments to check, if omitted all experiments marked with default=True are checked", 2024-12-17T23:28:37.4924422Z  ) 2024-12-17T23:28:37.4924881Z  parser.add_argument( 2024-12-17T23:28:37.4925456Z  "--pr-number", 2024-12-17T23:28:37.4926057Z  type=str, 2024-12-17T23:28:37.4926572Z  required=False, 2024-12-17T23:28:37.4927122Z  default="", 2024-12-17T23:28:37.4927810Z  help="the optional PR number where this is run", 2024-12-17T23:28:37.4928482Z  ) 2024-12-17T23:28:37.4928895Z  2024-12-17T23:28:37.4929434Z  return parser.parse_args() 2024-12-17T23:28:37.4930027Z  2024-12-17T23:28:37.4930428Z  2024-12-17T23:28:37.4931041Z def get_gh_client(github_token: str) -> Github: 2024-12-17T23:28:37.4931739Z  auth = Auth.Token(github_token) 2024-12-17T23:28:37.4932334Z  return Github(auth=auth) 2024-12-17T23:28:37.4932967Z  2024-12-17T23:28:37.4933401Z  2024-12-17T23:28:37.4933963Z def get_issue(gh: Github, repo: str, issue_num: int) -> Issue: 2024-12-17T23:28:37.4934785Z  repo = gh.get_repo(repo) 2024-12-17T23:28:37.4935422Z  return repo.get_issue(number=issue_num) 2024-12-17T23:28:37.4935998Z  2024-12-17T23:28:37.4936506Z  2024-12-17T23:28:37.4936980Z def get_potential_pr_author( 2024-12-17T23:28:37.4937719Z  github_token: str, repo: str, username: str, ref_type: str, ref_name: str 2024-12-17T23:28:37.4938561Z ) -> str: 2024-12-17T23:28:37.4939226Z  # If the trigger was a new tag added by a bot, this is a ciflow case 2024-12-17T23:28:37.4940258Z  # Fetch the actual username from the original PR. The PR number is 2024-12-17T23:28:37.4941248Z  # embedded in the tag name: ciflow// 2024-12-17T23:28:37.4941916Z  2024-12-17T23:28:37.4942386Z  gh = get_gh_client(github_token) 2024-12-17T23:28:37.4943036Z  2024-12-17T23:28:37.4943609Z  if username == "pytorch-bot[bot]" and ref_type == "tag": 2024-12-17T23:28:37.4944342Z  split_tag = ref_name.split("/") 2024-12-17T23:28:37.4944986Z  if ( 2024-12-17T23:28:37.4945775Z  len(split_tag) == 3 2024-12-17T23:28:37.4946399Z  and split_tag[0] == "ciflow" 2024-12-17T23:28:37.4947092Z  and split_tag[2].isnumeric() 2024-12-17T23:28:37.4947714Z  ): 2024-12-17T23:28:37.4948215Z  pr_number = split_tag[2] 2024-12-17T23:28:37.4948844Z  try: 2024-12-17T23:28:37.4949428Z  repository = gh.get_repo(repo) 2024-12-17T23:28:37.4950135Z  pull = repository.get_pull(number=int(pr_number)) 2024-12-17T23:28:37.4950893Z  except Exception as e: 2024-12-17T23:28:37.4951554Z  raise Exception( # noqa: TRY002 2024-12-17T23:28:37.4952315Z  f"issue with pull request {pr_number} from repo {repository}" 2024-12-17T23:28:37.4953153Z  ) from e 2024-12-17T23:28:37.4953703Z  return pull.user.login 2024-12-17T23:28:37.4954387Z  # In all other cases, return the original input username 2024-12-17T23:28:37.4955360Z  return username 2024-12-17T23:28:37.4955848Z  2024-12-17T23:28:37.4956269Z  2024-12-17T23:28:37.4956884Z def is_exception_branch(branch: str) -> bool: 2024-12-17T23:28:37.4957482Z  """ 2024-12-17T23:28:37.4958236Z  Branches that get opted out of experiments by default, until they're explicitly enabled. 2024-12-17T23:28:37.4959184Z  """ 2024-12-17T23:28:37.4959806Z  return branch.split("/")[0] in {"main", "nightly", "release", "landchecks"} 2024-12-17T23:28:37.4960544Z  2024-12-17T23:28:37.4961073Z  2024-12-17T23:28:37.4961520Z def load_yaml(yaml_text: str) -> Any: 2024-12-17T23:28:37.4962119Z  try: 2024-12-17T23:28:37.4962714Z  data = yaml.safe_load(yaml_text) 2024-12-17T23:28:37.4963709Z  return data 2024-12-17T23:28:37.4964663Z  except yaml.YAMLError: 2024-12-17T23:28:37.4965945Z  log.exception("Error loading YAML") 2024-12-17T23:28:37.4967054Z  raise 2024-12-17T23:28:37.4967924Z  2024-12-17T23:28:37.4968975Z  2024-12-17T23:28:37.4970335Z def extract_settings_user_opt_in_from_text(rollout_state: str) -> Tuple[str, str]: 2024-12-17T23:28:37.4971946Z  """ 2024-12-17T23:28:37.4973514Z  Extracts the text with settings, if any, and the opted in users from the rollout state. 2024-12-17T23:28:37.4975044Z  2024-12-17T23:28:37.4976087Z  If the issue body contains "---" then the text above that is the settings 2024-12-17T23:28:37.4977844Z  and the text below is the list of opted in users. 2024-12-17T23:28:37.4979109Z  2024-12-17T23:28:37.4980434Z  If it doesn't contain "---" then the settings are empty and the rest is the users. 2024-12-17T23:28:37.4981939Z  """ 2024-12-17T23:28:37.4983047Z  rollout_state_parts = rollout_state.split("---") 2024-12-17T23:28:37.4984580Z  if len(rollout_state_parts) >= 2: 2024-12-17T23:28:37.4986602Z  return rollout_state_parts[0], rollout_state_parts[1] 2024-12-17T23:28:37.4987887Z  else: 2024-12-17T23:28:37.4989217Z  return "", rollout_state 2024-12-17T23:28:37.4990349Z  2024-12-17T23:28:37.4991180Z  2024-12-17T23:28:37.4992304Z class UserOptins(Dict[str, List[str]]): 2024-12-17T23:28:37.4993333Z  """ 2024-12-17T23:28:37.4994354Z  Dictionary of users with a list of features they have opted into 2024-12-17T23:28:37.4995776Z  """ 2024-12-17T23:28:37.4996541Z  2024-12-17T23:28:37.4997271Z  2024-12-17T23:28:37.4998518Z def parse_user_opt_in_from_text(user_optin_text: str) -> UserOptins: 2024-12-17T23:28:37.4999890Z  """ 2024-12-17T23:28:37.5001411Z  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.5003293Z  2024-12-17T23:28:37.5004972Z  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.5007005Z  - Example line: "@User1,lf,split_build" 2024-12-17T23:28:37.5008569Z  - A "#" prefix indicates the user is opted out of all experiments 2024-12-17T23:28:37.5009951Z  2024-12-17T23:28:37.5010717Z  2024-12-17T23:28:37.5011716Z  """ 2024-12-17T23:28:37.5012569Z  optins = UserOptins() 2024-12-17T23:28:37.5013719Z  for user in user_optin_text.split("\n"): 2024-12-17T23:28:37.5015050Z  user = user.strip("\r\n\t -") 2024-12-17T23:28:37.5016193Z  if not user or not user.startswith("@"): 2024-12-17T23:28:37.5017279Z  # Not a valid user. Skip 2024-12-17T23:28:37.5019405Z  continue 2024-12-17T23:28:37.5020410Z  2024-12-17T23:28:37.5021821Z  if user: 2024-12-17T23:28:37.5023046Z  usr_name = user.split(",")[0].strip("@") 2024-12-17T23:28:37.5024476Z  optins[usr_name] = [exp.strip(" ") for exp in user.split(",")[1:]] 2024-12-17T23:28:37.5025979Z  2024-12-17T23:28:37.5026913Z  return optins 2024-12-17T23:28:37.5027945Z  2024-12-17T23:28:37.5028728Z  2024-12-17T23:28:37.5029985Z def is_valid_experiment_name(experiment_name: str) -> bool: 2024-12-17T23:28:37.5031277Z  """ 2024-12-17T23:28:37.5032129Z  Check if the experiment name is valid. 2024-12-17T23:28:37.5033482Z  A valid name: 2024-12-17T23:28:37.5035015Z  - Contains only alphanumeric characters and the special characters "_" & "-" 2024-12-17T23:28:37.5036997Z  - The special characters "_" & "-" shouldn't be the first or last characters 2024-12-17T23:28:37.5038724Z  - Cannot contain spaces 2024-12-17T23:28:37.5039818Z  """ 2024-12-17T23:28:37.5040675Z  2024-12-17T23:28:37.5041851Z  valid_char_regex = r"^[a-zA-Z0-9]([\w-]*[a-zA-Z0-9])?$" 2024-12-17T23:28:37.5043392Z  valid = bool(re.match(valid_char_regex, experiment_name)) 2024-12-17T23:28:37.5044573Z  2024-12-17T23:28:37.5045419Z  if valid: 2024-12-17T23:28:37.5046331Z  return True 2024-12-17T23:28:37.5047185Z  2024-12-17T23:28:37.5048000Z  log.error( 2024-12-17T23:28:37.5050682Z  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.5053680Z  ) 2024-12-17T23:28:37.5054463Z  return False 2024-12-17T23:28:37.5055504Z  2024-12-17T23:28:37.5056405Z  2024-12-17T23:28:37.5057450Z def parse_settings_from_text(settings_text: str) -> Settings: 2024-12-17T23:28:37.5058812Z  """ 2024-12-17T23:28:37.5060393Z  Parse the experiments from the issue body into a list of ExperimentSettings 2024-12-17T23:28:37.5061291Z  """ 2024-12-17T23:28:37.5061808Z  try: 2024-12-17T23:28:37.5062321Z  if settings_text: 2024-12-17T23:28:37.5063182Z  # 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.5064089Z  # for easy reading 2024-12-17T23:28:37.5065041Z  # Note: Using ascii for the backtick so that the cat step in _runner-determinator.yml doesn't choke on 2024-12-17T23:28:37.5066687Z  # the backtick character in shell commands. 2024-12-17T23:28:37.5067525Z  backtick = chr(96) # backtick character 2024-12-17T23:28:37.5068305Z  settings_text = settings_text.strip(f"\r\n\t{backtick} ") 2024-12-17T23:28:37.5069066Z  settings = load_yaml(settings_text) 2024-12-17T23:28:37.5069755Z  2024-12-17T23:28:37.5070414Z  # For now we just load experiments. We can expand this if/when we add more settings 2024-12-17T23:28:37.5071234Z  experiments = {} 2024-12-17T23:28:37.5071875Z  2024-12-17T23:28:37.5072490Z  for exp_name, exp_settings in settings.get(SETTING_EXPERIMENTS).items(): 2024-12-17T23:28:37.5073350Z  if not is_valid_experiment_name(exp_name): 2024-12-17T23:28:37.5074615Z  # 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.5075914Z  continue 2024-12-17T23:28:37.5076456Z  2024-12-17T23:28:37.5077004Z  valid_settings = {} 2024-12-17T23:28:37.5077640Z  for setting in exp_settings: 2024-12-17T23:28:37.5078306Z  if setting not in Experiment._fields: 2024-12-17T23:28:37.5079066Z  log.warning( 2024-12-17T23:28:37.5080495Z  f"Unexpected setting in experiment: {setting} = {exp_settings[setting]}" 2024-12-17T23:28:37.5081540Z  ) 2024-12-17T23:28:37.5082193Z  else: 2024-12-17T23:28:37.5083280Z  valid_settings[setting] = exp_settings[setting] 2024-12-17T23:28:37.5084345Z  2024-12-17T23:28:37.5085026Z  experiments[exp_name] = Experiment(**valid_settings) 2024-12-17T23:28:37.5085787Z  return Settings(experiments) 2024-12-17T23:28:37.5086396Z  2024-12-17T23:28:37.5086899Z  except Exception: 2024-12-17T23:28:37.5087534Z  log.exception("Failed to parse settings") 2024-12-17T23:28:37.5088154Z  2024-12-17T23:28:37.5088646Z  return Settings() 2024-12-17T23:28:37.5089188Z  2024-12-17T23:28:37.5089600Z  2024-12-17T23:28:37.5090193Z def parse_settings(rollout_state: str) -> Settings: 2024-12-17T23:28:37.5090904Z  """ 2024-12-17T23:28:37.5091445Z  Parse settings, if any, from the rollout state. 2024-12-17T23:28:37.5092133Z  2024-12-17T23:28:37.5092782Z  If the issue body contains "---" then the text above that is the settings 2024-12-17T23:28:37.5093626Z  and the text below is the list of opted in users. 2024-12-17T23:28:37.5094315Z  2024-12-17T23:28:37.5095021Z  If it doesn't contain "---" then the settings are empty and the default values are used. 2024-12-17T23:28:37.5096400Z  """ 2024-12-17T23:28:37.5097404Z  settings_text, _ = extract_settings_user_opt_in_from_text(rollout_state) 2024-12-17T23:28:37.5098241Z  return parse_settings_from_text(settings_text) 2024-12-17T23:28:37.5098934Z  2024-12-17T23:28:37.5099661Z  2024-12-17T23:28:37.5100216Z def parse_users(rollout_state: str) -> UserOptins: 2024-12-17T23:28:37.5100867Z  """ 2024-12-17T23:28:37.5101483Z  Parse users from the rollout state. 2024-12-17T23:28:37.5102046Z  2024-12-17T23:28:37.5102478Z  """ 2024-12-17T23:28:37.5103211Z  _, users_text = extract_settings_user_opt_in_from_text(rollout_state) 2024-12-17T23:28:37.5104028Z  return parse_user_opt_in_from_text(users_text) 2024-12-17T23:28:37.5104667Z  2024-12-17T23:28:37.5105168Z  2024-12-17T23:28:37.5106117Z def is_user_opted_in(user: str, user_optins: UserOptins, experiment_name: str) -> bool: 2024-12-17T23:28:37.5106992Z  """ 2024-12-17T23:28:37.5107643Z  Check if a user is opted into an experiment 2024-12-17T23:28:37.5108241Z  """ 2024-12-17T23:28:37.5108836Z  return experiment_name in user_optins.get(user, []) 2024-12-17T23:28:37.5109584Z  2024-12-17T23:28:37.5109983Z  2024-12-17T23:28:37.5110701Z def is_user_opted_out(user: str, user_optins: UserOptins, experiment_name: str) -> bool: 2024-12-17T23:28:37.5112013Z  """ 2024-12-17T23:28:37.5112818Z  Check if a user explicitly opted out of an experiment 2024-12-17T23:28:37.5113447Z  """ 2024-12-17T23:28:37.5114166Z  # if the experiment is prefixed with a "-", then it's an opt-out 2024-12-17T23:28:37.5115034Z  experiment_optout = "-" + experiment_name 2024-12-17T23:28:37.5115849Z  if experiment_optout not in user_optins.get(user, []): 2024-12-17T23:28:37.5116750Z  return False 2024-12-17T23:28:37.5117275Z  2024-12-17T23:28:37.5117893Z  if is_user_opted_in(user, user_optins, experiment_name): 2024-12-17T23:28:37.5118586Z  log.warning( 2024-12-17T23:28:37.5119514Z  f"User {user} is opted into experiment {experiment_name}, but also opted out of it. Defaulting to opting out" 2024-12-17T23:28:37.5120533Z  ) 2024-12-17T23:28:37.5120979Z  2024-12-17T23:28:37.5121403Z  return True 2024-12-17T23:28:37.5121948Z  2024-12-17T23:28:37.5122396Z  2024-12-17T23:28:37.5122834Z def get_runner_prefix( 2024-12-17T23:28:37.5123433Z  rollout_state: str, 2024-12-17T23:28:37.5124083Z  workflow_requestors: Iterable[str], 2024-12-17T23:28:37.5124676Z  branch: str, 2024-12-17T23:28:37.5125381Z  eligible_experiments: FrozenSet[str] = frozenset(), 2024-12-17T23:28:37.5126065Z  is_canary: bool = False, 2024-12-17T23:28:37.5126617Z ) -> str: 2024-12-17T23:28:37.5127246Z  settings = parse_settings(rollout_state) 2024-12-17T23:28:37.5127893Z  user_optins = parse_users(rollout_state) 2024-12-17T23:28:37.5128493Z  2024-12-17T23:28:37.5129157Z  fleet_prefix = "" 2024-12-17T23:28:37.5130002Z  prefixes = [] 2024-12-17T23:28:37.5131208Z  for experiment_name, experiment_settings in settings.experiments.items(): 2024-12-17T23:28:37.5132894Z  if not experiment_settings.all_branches and is_exception_branch(branch): 2024-12-17T23:28:37.5133681Z  log.info( 2024-12-17T23:28:37.5134479Z  f"Branch {branch} is an exception branch. Not enabling experiment {experiment_name}." 2024-12-17T23:28:37.5135413Z  ) 2024-12-17T23:28:37.5135955Z  continue 2024-12-17T23:28:37.5136489Z  2024-12-17T23:28:37.5136991Z  if eligible_experiments: 2024-12-17T23:28:37.5137683Z  if experiment_name not in eligible_experiments: 2024-12-17T23:28:37.5138449Z  exp_list = ", ".join(eligible_experiments) 2024-12-17T23:28:37.5139269Z  log.info( 2024-12-17T23:28:37.5140199Z  f"Skipping experiment '{experiment_name}', as it is not in the eligible_experiments list: {exp_list}" 2024-12-17T23:28:37.5141115Z  ) 2024-12-17T23:28:37.5141665Z  continue 2024-12-17T23:28:37.5142297Z  elif not experiment_settings.default: 2024-12-17T23:28:37.5142942Z  log.info( 2024-12-17T23:28:37.5143742Z  f"Skipping experiment '{experiment_name}', as it is not a default experiment" 2024-12-17T23:28:37.5144566Z  ) 2024-12-17T23:28:37.5145123Z  continue 2024-12-17T23:28:37.5145880Z  2024-12-17T23:28:37.5146467Z  # Is any workflow_requestor opted out to this experiment? 2024-12-17T23:28:37.5147255Z  opted_out_users = [ 2024-12-17T23:28:37.5147791Z  requestor 2024-12-17T23:28:37.5148407Z  for requestor in workflow_requestors 2024-12-17T23:28:37.5149260Z  if is_user_opted_out(requestor, user_optins, experiment_name) 2024-12-17T23:28:37.5149937Z  ] 2024-12-17T23:28:37.5150419Z  2024-12-17T23:28:37.5150932Z  if opted_out_users: 2024-12-17T23:28:37.5151483Z  log.info( 2024-12-17T23:28:37.5152226Z  f"{', '.join(opted_out_users)} have opted out of experiment {experiment_name}." 2024-12-17T23:28:37.5153050Z  ) 2024-12-17T23:28:37.5153528Z  continue 2024-12-17T23:28:37.5154047Z  2024-12-17T23:28:37.5154868Z  # Is any workflow_requestor opted in to this experiment? 2024-12-17T23:28:37.5155524Z  opted_in_users = [ 2024-12-17T23:28:37.5156081Z  requestor 2024-12-17T23:28:37.5156769Z  for requestor in workflow_requestors 2024-12-17T23:28:37.5157537Z  if is_user_opted_in(requestor, user_optins, experiment_name) 2024-12-17T23:28:37.5158194Z  ] 2024-12-17T23:28:37.5158732Z  2024-12-17T23:28:37.5159172Z  enabled = False 2024-12-17T23:28:37.5159692Z  if opted_in_users: 2024-12-17T23:28:37.5160331Z  log.info( 2024-12-17T23:28:37.5161059Z  f"{', '.join(opted_in_users)} have opted into experiment {experiment_name}." 2024-12-17T23:28:37.5161780Z  ) 2024-12-17T23:28:37.5162373Z  enabled = True 2024-12-17T23:28:37.5162936Z  2024-12-17T23:28:37.5163448Z  elif experiment_settings.rollout_perc: 2024-12-17T23:28:37.5164459Z  # If no user is opted in, then we randomly enable the experiment based on the rollout percentage 2024-12-17T23:28:37.5165472Z  if random.uniform(0, 100) <= experiment_settings.rollout_perc: 2024-12-17T23:28:37.5166202Z  log.info( 2024-12-17T23:28:37.5167210Z  f"Based on rollout percentage of {experiment_settings.rollout_perc}%, enabling experiment {experiment_name}." 2024-12-17T23:28:37.5168225Z  ) 2024-12-17T23:28:37.5168758Z  enabled = True 2024-12-17T23:28:37.5169372Z  2024-12-17T23:28:37.5169812Z  if enabled: 2024-12-17T23:28:37.5170364Z  label = experiment_name 2024-12-17T23:28:37.5171063Z  if experiment_name == LF_FLEET_EXPERIMENT: 2024-12-17T23:28:37.5171978Z  # We give some special treatment to the "lf" experiment since determines the fleet we use 2024-12-17T23:28:37.5172925Z  # - If it's enabled, then we always list it's prefix first 2024-12-17T23:28:37.5175105Z  # - If we're in the canary branch, then we append ".c" to the lf prefix 2024-12-17T23:28:37.5176367Z  if is_canary: 2024-12-17T23:28:37.5177368Z  label += CANARY_FLEET_SUFFIX 2024-12-17T23:28:37.5178594Z  fleet_prefix = label 2024-12-17T23:28:37.5179653Z  else: 2024-12-17T23:28:37.5180519Z  prefixes.append(label) 2024-12-17T23:28:37.5181660Z  2024-12-17T23:28:37.5182394Z  if len(prefixes) > 1: 2024-12-17T23:28:37.5183290Z  log.error( 2024-12-17T23:28:37.5185726Z  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.5187920Z  ) 2024-12-17T23:28:37.5188710Z  prefixes = prefixes[:1] 2024-12-17T23:28:37.5189797Z  2024-12-17T23:28:37.5190573Z  # Fleet always comes first 2024-12-17T23:28:37.5191492Z  if fleet_prefix: 2024-12-17T23:28:37.5192674Z  prefixes.insert(0, fleet_prefix) 2024-12-17T23:28:37.5193673Z  2024-12-17T23:28:37.5194503Z  return ".".join(prefixes) + "." if prefixes else "" 2024-12-17T23:28:37.5195794Z  2024-12-17T23:28:37.5196487Z  2024-12-17T23:28:37.5197619Z def get_rollout_state_from_issue(github_token: str, repo: str, issue_num: int) -> str: 2024-12-17T23:28:37.5199155Z  """ 2024-12-17T23:28:37.5200386Z  Gets the first comment of the issue, which contains the desired rollout state. 2024-12-17T23:28:37.5201284Z  2024-12-17T23:28:37.5202218Z  The default issue we use - https://github.com/pytorch/test-infra/issues/5132 2024-12-17T23:28:37.5202989Z  """ 2024-12-17T23:28:37.5203585Z  gh = get_gh_client(github_token) 2024-12-17T23:28:37.5204241Z  issue = get_issue(gh, repo, issue_num) 2024-12-17T23:28:37.5205386Z  return str(issue.get_comments()[0].body.strip("\n\t ")) 2024-12-17T23:28:37.5206676Z  2024-12-17T23:28:37.5207313Z  2024-12-17T23:28:37.5208015Z def download_json(url: str, headers: Dict[str, str], num_retries: int = 3) -> Any: 2024-12-17T23:28:37.5208863Z  for _ in range(num_retries): 2024-12-17T23:28:37.5209486Z  try: 2024-12-17T23:28:37.5210052Z  req = Request(url=url, headers=headers) 2024-12-17T23:28:37.5210806Z  content = urlopen(req, timeout=5).read().decode("utf-8") 2024-12-17T23:28:37.5211584Z  return json.loads(content) 2024-12-17T23:28:37.5212233Z  except Exception as e: 2024-12-17T23:28:37.5212876Z  log.warning(f"Could not download {url}: {e}") 2024-12-17T23:28:37.5213559Z  2024-12-17T23:28:37.5214243Z  log.warning(f"All {num_retries} retries exhausted, downloading {url} failed") 2024-12-17T23:28:37.5215026Z  return {} 2024-12-17T23:28:37.5215563Z  2024-12-17T23:28:37.5216004Z  2024-12-17T23:28:37.5216441Z @lru_cache(maxsize=None) 2024-12-17T23:28:37.5217350Z def get_pr_info(github_repo: str, github_token: str, pr_number: int) -> Dict[str, Any]: 2024-12-17T23:28:37.5218146Z  """ 2024-12-17T23:28:37.5218649Z  Dynamically get PR information 2024-12-17T23:28:37.5219324Z  """ 2024-12-17T23:28:37.5219901Z  github_api = f"https://api.github.com/repos/{github_repo}" 2024-12-17T23:28:37.5220602Z  headers = { 2024-12-17T23:28:37.5221293Z  "Accept": "application/vnd.github.v3+json", 2024-12-17T23:28:37.5221962Z  "Authorization": f"token {github_token}", 2024-12-17T23:28:37.5222565Z  } 2024-12-17T23:28:37.5223204Z  json_response: Dict[str, Any] = download_json( 2024-12-17T23:28:37.5224057Z  url=f"{github_api}/issues/{pr_number}", 2024-12-17T23:28:37.5224696Z  headers=headers, 2024-12-17T23:28:37.5225674Z  ) 2024-12-17T23:28:37.5226436Z  2024-12-17T23:28:37.5227223Z  if not json_response: 2024-12-17T23:28:37.5228742Z  log.warning(f"Failed to get the labels for #{pr_number}") 2024-12-17T23:28:37.5230063Z  return {} 2024-12-17T23:28:37.5230943Z  2024-12-17T23:28:37.5231764Z  return json_response 2024-12-17T23:28:37.5232871Z  2024-12-17T23:28:37.5233620Z  2024-12-17T23:28:37.5234779Z def get_labels(github_repo: str, github_token: str, pr_number: int) -> Set[str]: 2024-12-17T23:28:37.5235813Z  """ 2024-12-17T23:28:37.5236462Z  Dynamically get the latest list of labels from the pull request 2024-12-17T23:28:37.5237214Z  """ 2024-12-17T23:28:37.5237895Z  pr_info = get_pr_info(github_repo, github_token, pr_number) 2024-12-17T23:28:37.5238579Z  return { 2024-12-17T23:28:37.5239293Z  label.get("name") for label in pr_info.get("labels", []) if label.get("name") 2024-12-17T23:28:37.5240140Z  } 2024-12-17T23:28:37.5240560Z  2024-12-17T23:28:37.5240988Z  2024-12-17T23:28:37.5241518Z def main() -> None: 2024-12-17T23:28:37.5242029Z  args = parse_args() 2024-12-17T23:28:37.5242561Z  2024-12-17T23:28:37.5243175Z  runner_label_prefix = DEFAULT_LABEL_PREFIX 2024-12-17T23:28:37.5243775Z  2024-12-17T23:28:37.5244250Z  # Check if the PR is opt-out 2024-12-17T23:28:37.5245151Z  if args.pr_number: 2024-12-17T23:28:37.5245897Z  labels = get_labels(args.github_repo, args.github_token, int(args.pr_number)) 2024-12-17T23:28:37.5246746Z  if OPT_OUT_LABEL in labels: 2024-12-17T23:28:37.5247414Z  log.info( 2024-12-17T23:28:37.5248227Z  f"Opt-out runner determinator because #{args.pr_number} has {OPT_OUT_LABEL} label" 2024-12-17T23:28:37.5249130Z  ) 2024-12-17T23:28:37.5249874Z  set_github_output(GH_OUTPUT_KEY_LABEL_TYPE, runner_label_prefix) 2024-12-17T23:28:37.5250625Z  sys.exit() 2024-12-17T23:28:37.5251130Z  2024-12-17T23:28:37.5251633Z  try: 2024-12-17T23:28:37.5252197Z  rollout_state = get_rollout_state_from_issue( 2024-12-17T23:28:37.5252985Z  args.github_token, args.github_issue_repo, args.github_issue 2024-12-17T23:28:37.5253770Z  ) 2024-12-17T23:28:37.5254483Z  2024-12-17T23:28:37.5255293Z  username = get_potential_pr_author( 2024-12-17T23:28:37.5256072Z  args.github_token, 2024-12-17T23:28:37.5256688Z  args.github_repo, 2024-12-17T23:28:37.5257254Z  args.github_actor, 2024-12-17T23:28:37.5257928Z  args.github_ref_type, 2024-12-17T23:28:37.5258540Z  args.github_branch, 2024-12-17T23:28:37.5259108Z  ) 2024-12-17T23:28:37.5259632Z  2024-12-17T23:28:37.5260226Z  is_canary = args.github_repo == "pytorch/pytorch-canary" 2024-12-17T23:28:37.5260895Z  2024-12-17T23:28:37.5261448Z  runner_label_prefix = get_runner_prefix( 2024-12-17T23:28:37.5262099Z  rollout_state, 2024-12-17T23:28:37.5262690Z  (args.github_issue_owner, username), 2024-12-17T23:28:37.5263377Z  args.github_branch, 2024-12-17T23:28:37.5264017Z  args.eligible_experiments, 2024-12-17T23:28:37.5264609Z  is_canary, 2024-12-17T23:28:37.5265193Z  ) 2024-12-17T23:28:37.5266052Z  2024-12-17T23:28:37.5266499Z  except Exception as e: 2024-12-17T23:28:37.5267348Z  log.error( 2024-12-17T23:28:37.5268177Z  f"Failed to get issue. Defaulting to Meta runners and no experiments. Exception: {e}" 2024-12-17T23:28:37.5269029Z  ) 2024-12-17T23:28:37.5269557Z  2024-12-17T23:28:37.5270174Z  set_github_output(GH_OUTPUT_KEY_LABEL_TYPE, runner_label_prefix) 2024-12-17T23:28:37.5270902Z  2024-12-17T23:28:37.5271366Z  2024-12-17T23:28:37.5271811Z if __name__ == "__main__": 2024-12-17T23:28:37.5272364Z  main() 2024-12-17T23:28:37.5272870Z  2024-12-17T23:28:37.5273299Z EOF 2024-12-17T23:28:37.5273747Z  2024-12-17T23:28:37.5274265Z cat runner_determinator.py 2024-12-17T23:28:37.5749638Z shell: /usr/bin/bash -e {0} 2024-12-17T23:28:37.5750512Z env: 2024-12-17T23:28:37.5751195Z GITHUB_TOKEN: *** 2024-12-17T23:28:37.5751796Z ISSUE_NUMBER: 5132 2024-12-17T23:28:37.5752276Z TRIGGERING_ACTOR: malfet 2024-12-17T23:28:37.5752802Z ISSUE_OWNER: 2024-12-17T23:28:37.5753370Z CHECK_EXPERIMENTS: 2024-12-17T23:28:37.5753831Z PR_NUMBER: 2024-12-17T23:28:37.5754301Z ##[endgroup] 2024-12-17T23:28:37.6028354Z # flake8: noqa: G004 2024-12-17T23:28:37.6028712Z 2024-12-17T23:28:37.6029287Z # Note: Copies of this script in runner_determinator.py and _runner-determinator.yml 2024-12-17T23:28:37.6030299Z # must be kept in sync. You can do it easily by running the following command: 2024-12-17T23:28:37.6031156Z # python .github/scripts/update_runner_determinator.py 2024-12-17T23:28:37.6031609Z 2024-12-17T23:28:37.6032247Z """ 2024-12-17T23:28:37.6033173Z This runner determinator is used to determine which set of runners to run a 2024-12-17T23:28:37.6034116Z GitHub job on. It uses the first comment of a GitHub issue (by default 2024-12-17T23:28:37.6035122Z https://github.com/pytorch/test-infra/issues/5132) to define the configuration 2024-12-17T23:28:37.6035981Z of which runners should be used to run which job. 2024-12-17T23:28:37.6036443Z 2024-12-17T23:28:37.6036832Z The configuration has two parts, the settings and a list of opted-in users, 2024-12-17T23:28:37.6037806Z separated by a line containing "---". If the line is not present, the 2024-12-17T23:28:37.6038746Z settings are considered to be empty with only the second part, the user 2024-12-17T23:28:37.6039451Z list, defined. 2024-12-17T23:28:37.6039714Z 2024-12-17T23:28:37.6040156Z The first part is a YAML block that defines the rollout settings. This can be 2024-12-17T23:28:37.6041143Z used to define any settings that are needed to determine which runners to use. 2024-12-17T23:28:37.6041986Z It's fields are defined by the RolloutSettings class below. 2024-12-17T23:28:37.6042463Z 2024-12-17T23:28:37.6042902Z The second part is a list of users who are explicitly opted in to the LF fleet. 2024-12-17T23:28:37.6043843Z The user list is also a comma separated list of additional features or 2024-12-17T23:28:37.6044595Z experiments which the user could be opted in to. 2024-12-17T23:28:37.6045027Z 2024-12-17T23:28:37.6045309Z The user list has the following rules: 2024-12-17T23:28:37.6045740Z 2024-12-17T23:28:37.6046074Z - Users are GitHub usernames, which must start with the @ prefix 2024-12-17T23:28:37.6046968Z - Each user is also a comma-separated list of features/experiments to enable 2024-12-17T23:28:37.6047826Z - A "#" prefix opts the user out of all experiments 2024-12-17T23:28:37.6048307Z 2024-12-17T23:28:37.6048497Z Example config: 2024-12-17T23:28:37.6049008Z # A list of experiments that can be opted into. 2024-12-17T23:28:37.6049738Z # This defines the behavior they'll induce when opted into. 2024-12-17T23:28:37.6050467Z # Expected syntax is: 2024-12-17T23:28:37.6051161Z # [experiment_name]: # Name of the experiment. Also used for the label prefix. 2024-12-17T23:28:37.6052180Z # rollout_perc: [int] # % of workflows to run with this experiment when users are not opted in. 2024-12-17T23:28:37.6052853Z 2024-12-17T23:28:37.6053205Z experiments: 2024-12-17T23:28:37.6053692Z lf: 2024-12-17T23:28:37.6054189Z rollout_percent: 25 2024-12-17T23:28:37.6054744Z all_branches: false 2024-12-17T23:28:37.6055287Z default: true 2024-12-17T23:28:37.6055780Z --- 2024-12-17T23:28:37.6056050Z 2024-12-17T23:28:37.6056232Z # Opt-ins: 2024-12-17T23:28:37.6056887Z # Users can opt into the LF fleet by adding their GitHub username to this list 2024-12-17T23:28:37.6057870Z # and specifying experiments to enable in a comma-separated list. 2024-12-17T23:28:37.6058662Z # To always opt out of an experiment, prefix it with a "-". 2024-12-17T23:28:37.6059380Z # Experiments should be from the above list. 2024-12-17T23:28:37.6059752Z 2024-12-17T23:28:37.6060058Z @User1,-lf,split_build 2024-12-17T23:28:37.6060524Z @User2,lf 2024-12-17T23:28:37.6061016Z @User3,split_build 2024-12-17T23:28:37.6061549Z """ 2024-12-17T23:28:37.6061755Z 2024-12-17T23:28:37.6061945Z import json 2024-12-17T23:28:37.6062395Z import logging 2024-12-17T23:28:37.6062903Z import os 2024-12-17T23:28:37.6063298Z import random 2024-12-17T23:28:37.6063753Z import re 2024-12-17T23:28:37.6064232Z import sys 2024-12-17T23:28:37.6064677Z from argparse import ArgumentParser 2024-12-17T23:28:37.6065493Z from functools import lru_cache 2024-12-17T23:28:37.6066126Z from logging import LogRecord 2024-12-17T23:28:37.6066920Z from typing import Any, Dict, FrozenSet, Iterable, List, NamedTuple, Set, Tuple 2024-12-17T23:28:37.6067728Z from urllib.request import Request, urlopen 2024-12-17T23:28:37.6068090Z 2024-12-17T23:28:37.6068388Z import yaml 2024-12-17T23:28:37.6068825Z from github import Auth, Github 2024-12-17T23:28:37.6069554Z from github.Issue import Issue 2024-12-17T23:28:37.6069855Z 2024-12-17T23:28:37.6069860Z 2024-12-17T23:28:37.6070238Z DEFAULT_LABEL_PREFIX = "" # use meta runners 2024-12-17T23:28:37.6070940Z WORKFLOW_LABEL_LF = "lf." # use runners from the linux foundation 2024-12-17T23:28:37.6071849Z WORKFLOW_LABEL_LF_CANARY = "lf.c." # use canary runners from the linux foundation 2024-12-17T23:28:37.6072389Z 2024-12-17T23:28:37.6072770Z GITHUB_OUTPUT = os.getenv("GITHUB_OUTPUT", "") 2024-12-17T23:28:37.6073363Z GH_OUTPUT_KEY_AMI = "runner-ami" 2024-12-17T23:28:37.6073927Z GH_OUTPUT_KEY_LABEL_TYPE = "label-type" 2024-12-17T23:28:37.6074612Z OPT_OUT_LABEL = "no-runner-experiments" 2024-12-17T23:28:37.6074980Z 2024-12-17T23:28:37.6075188Z SETTING_EXPERIMENTS = "experiments" 2024-12-17T23:28:37.6075563Z 2024-12-17T23:28:37.6075769Z LF_FLEET_EXPERIMENT = "lf" 2024-12-17T23:28:37.6076381Z CANARY_FLEET_SUFFIX = ".c" 2024-12-17T23:28:37.6076678Z 2024-12-17T23:28:37.6076693Z 2024-12-17T23:28:37.6076936Z class Experiment(NamedTuple): 2024-12-17T23:28:37.6077443Z rollout_perc: float = ( 2024-12-17T23:28:37.6078218Z 0 # Percentage of workflows to experiment on when user is not opted-in. 2024-12-17T23:28:37.6078943Z ) 2024-12-17T23:28:37.6079355Z all_branches: bool = ( 2024-12-17T23:28:37.6080109Z False # If True, the experiment is also enabled on the exception branches 2024-12-17T23:28:37.6080832Z ) 2024-12-17T23:28:37.6081236Z default: bool = ( 2024-12-17T23:28:37.6081934Z True # If True, the experiment is enabled by default for all queries 2024-12-17T23:28:37.6082621Z ) 2024-12-17T23:28:37.6082847Z 2024-12-17T23:28:37.6083045Z # Add more fields as needed 2024-12-17T23:28:37.6083442Z 2024-12-17T23:28:37.6083448Z 2024-12-17T23:28:37.6083673Z class Settings(NamedTuple): 2024-12-17T23:28:37.6084172Z """ 2024-12-17T23:28:37.6084666Z Settings for the experiments that can be opted into. 2024-12-17T23:28:37.6085371Z """ 2024-12-17T23:28:37.6085593Z 2024-12-17T23:28:37.6085863Z experiments: Dict[str, Experiment] = {} 2024-12-17T23:28:37.6086236Z 2024-12-17T23:28:37.6086242Z 2024-12-17T23:28:37.6086464Z class ColorFormatter(logging.Formatter): 2024-12-17T23:28:37.6087206Z """Color codes the log messages based on the log level""" 2024-12-17T23:28:37.6087837Z 2024-12-17T23:28:37.6088036Z COLORS = { 2024-12-17T23:28:37.6088489Z "WARNING": "\033[33m", # Yellow 2024-12-17T23:28:37.6089128Z "ERROR": "\033[31m", # Red 2024-12-17T23:28:37.6089689Z "CRITICAL": "\033[31m", # Red 2024-12-17T23:28:37.6090223Z "INFO": "\033[0m", # Reset 2024-12-17T23:28:37.6090801Z "DEBUG": "\033[0m", # Reset 2024-12-17T23:28:37.6091347Z } 2024-12-17T23:28:37.6091550Z 2024-12-17T23:28:37.6091802Z def format(self, record: LogRecord) -> str: 2024-12-17T23:28:37.6092649Z log_color = self.COLORS.get(record.levelname, "\033[0m") # Default to reset 2024-12-17T23:28:37.6093471Z record.msg = f"{log_color}{record.msg}\033[0m" 2024-12-17T23:28:37.6094089Z return super().format(record) 2024-12-17T23:28:37.6094500Z 2024-12-17T23:28:37.6094506Z 2024-12-17T23:28:37.6094751Z handler = logging.StreamHandler() 2024-12-17T23:28:37.6095508Z handler.setFormatter(ColorFormatter(fmt="%(levelname)-8s: %(message)s")) 2024-12-17T23:28:37.6096054Z 2024-12-17T23:28:37.6096351Z log = logging.getLogger(os.path.basename(__file__)) 2024-12-17T23:28:37.6097065Z log.addHandler(handler) 2024-12-17T23:28:37.6097573Z log.setLevel(logging.INFO) 2024-12-17T23:28:37.6097903Z 2024-12-17T23:28:37.6097910Z 2024-12-17T23:28:37.6098154Z def set_github_output(key: str, value: str) -> None: 2024-12-17T23:28:37.6098855Z """ 2024-12-17T23:28:37.6099385Z Defines outputs of the github action that invokes this script 2024-12-17T23:28:37.6100035Z """ 2024-12-17T23:28:37.6100568Z if not GITHUB_OUTPUT: 2024-12-17T23:28:37.6101624Z # 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.6102898Z log.warning( 2024-12-17T23:28:37.6103867Z "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.6104775Z ) 2024-12-17T23:28:37.6114799Z print(f"::set-output name={key}::{value}") 2024-12-17T23:28:37.6115611Z return 2024-12-17T23:28:37.6115860Z 2024-12-17T23:28:37.6116074Z with open(GITHUB_OUTPUT, "a") as f: 2024-12-17T23:28:37.6116718Z log.info(f"Setting output: {key}='{value}'") 2024-12-17T23:28:37.6117441Z f.write(f"{key}={value}\n") 2024-12-17T23:28:37.6117787Z 2024-12-17T23:28:37.6117794Z 2024-12-17T23:28:37.6118162Z def _str_comma_separated_to_set(value: str) -> FrozenSet[str]: 2024-12-17T23:28:37.6118807Z return frozenset( 2024-12-17T23:28:37.6119553Z filter(lambda itm: itm != "", map(str.strip, value.strip(" \n\t").split(","))) 2024-12-17T23:28:37.6120316Z ) 2024-12-17T23:28:37.6120526Z 2024-12-17T23:28:37.6120533Z 2024-12-17T23:28:37.6120719Z def parse_args() -> Any: 2024-12-17T23:28:37.6121428Z parser = ArgumentParser("Get dynamic rollout settings") 2024-12-17T23:28:37.6122358Z parser.add_argument("--github-token", type=str, required=True, help="GitHub token") 2024-12-17T23:28:37.6123149Z parser.add_argument( 2024-12-17T23:28:37.6123754Z "--github-issue-repo", 2024-12-17T23:28:37.6124295Z type=str, 2024-12-17T23:28:37.6124711Z required=False, 2024-12-17T23:28:37.6125315Z default="pytorch/test-infra", 2024-12-17T23:28:37.6125913Z help="GitHub repo to get the issue", 2024-12-17T23:28:37.6126435Z ) 2024-12-17T23:28:37.6126965Z parser.add_argument( 2024-12-17T23:28:37.6127469Z "--github-repo", 2024-12-17T23:28:37.6127963Z type=str, 2024-12-17T23:28:37.6128522Z required=True, 2024-12-17T23:28:37.6129051Z help="GitHub repo where CI is running", 2024-12-17T23:28:37.6129588Z ) 2024-12-17T23:28:37.6130119Z parser.add_argument( 2024-12-17T23:28:37.6130783Z "--github-issue", type=int, required=True, help="GitHub issue number" 2024-12-17T23:28:37.6131439Z ) 2024-12-17T23:28:37.6131961Z parser.add_argument( 2024-12-17T23:28:37.6132831Z "--github-actor", type=str, required=True, help="GitHub triggering_actor" 2024-12-17T23:28:37.6133559Z ) 2024-12-17T23:28:37.6134085Z parser.add_argument( 2024-12-17T23:28:37.6134778Z "--github-issue-owner", type=str, required=True, help="GitHub issue owner" 2024-12-17T23:28:37.6135481Z ) 2024-12-17T23:28:37.6135998Z parser.add_argument( 2024-12-17T23:28:37.6136707Z "--github-branch", type=str, required=True, help="Current GitHub branch or tag" 2024-12-17T23:28:37.6137432Z ) 2024-12-17T23:28:37.6137934Z parser.add_argument( 2024-12-17T23:28:37.6138456Z "--github-ref-type", 2024-12-17T23:28:37.6138916Z type=str, 2024-12-17T23:28:37.6139455Z required=True, 2024-12-17T23:28:37.6140013Z help="Current GitHub ref type, branch or tag", 2024-12-17T23:28:37.6140569Z ) 2024-12-17T23:28:37.6141077Z parser.add_argument( 2024-12-17T23:28:37.6141616Z "--eligible-experiments", 2024-12-17T23:28:37.6142141Z type=_str_comma_separated_to_set, 2024-12-17T23:28:37.6142810Z required=False, 2024-12-17T23:28:37.6143306Z default="", 2024-12-17T23:28:37.6144139Z help="comma separated list of experiments to check, if omitted all experiments marked with default=True are checked", 2024-12-17T23:28:37.6145168Z ) 2024-12-17T23:28:37.6146712Z parser.add_argument( 2024-12-17T23:28:37.6147184Z "--pr-number", 2024-12-17T23:28:37.6147769Z type=str, 2024-12-17T23:28:37.6148246Z required=False, 2024-12-17T23:28:37.6148681Z default="", 2024-12-17T23:28:37.6149310Z help="the optional PR number where this is run", 2024-12-17T23:28:37.6149921Z ) 2024-12-17T23:28:37.6150340Z 2024-12-17T23:28:37.6150537Z return parser.parse_args() 2024-12-17T23:28:37.6151004Z 2024-12-17T23:28:37.6151012Z 2024-12-17T23:28:37.6151264Z def get_gh_client(github_token: str) -> Github: 2024-12-17T23:28:37.6151888Z auth = Auth.Token(github_token) 2024-12-17T23:28:37.6152396Z return Github(auth=auth) 2024-12-17T23:28:37.6152839Z 2024-12-17T23:28:37.6152845Z 2024-12-17T23:28:37.6153156Z def get_issue(gh: Github, repo: str, issue_num: int) -> Issue: 2024-12-17T23:28:37.6153839Z repo = gh.get_repo(repo) 2024-12-17T23:28:37.6154343Z return repo.get_issue(number=issue_num) 2024-12-17T23:28:37.6154841Z 2024-12-17T23:28:37.6154847Z 2024-12-17T23:28:37.6155051Z def get_potential_pr_author( 2024-12-17T23:28:37.6155734Z github_token: str, repo: str, username: str, ref_type: str, ref_name: str 2024-12-17T23:28:37.6156519Z ) -> str: 2024-12-17T23:28:37.6157069Z # If the trigger was a new tag added by a bot, this is a ciflow case 2024-12-17T23:28:37.6157911Z # Fetch the actual username from the original PR. The PR number is 2024-12-17T23:28:37.6158787Z # embedded in the tag name: ciflow// 2024-12-17T23:28:37.6159226Z 2024-12-17T23:28:37.6159430Z gh = get_gh_client(github_token) 2024-12-17T23:28:37.6159810Z 2024-12-17T23:28:37.6160095Z if username == "pytorch-bot[bot]" and ref_type == "tag": 2024-12-17T23:28:37.6160835Z split_tag = ref_name.split("/") 2024-12-17T23:28:37.6161372Z if ( 2024-12-17T23:28:37.6161819Z len(split_tag) == 3 2024-12-17T23:28:37.6162429Z and split_tag[0] == "ciflow" 2024-12-17T23:28:37.6162987Z and split_tag[2].isnumeric() 2024-12-17T23:28:37.6163555Z ): 2024-12-17T23:28:37.6164050Z pr_number = split_tag[2] 2024-12-17T23:28:37.6164572Z try: 2024-12-17T23:28:37.6165072Z repository = gh.get_repo(repo) 2024-12-17T23:28:37.6165789Z pull = repository.get_pull(number=int(pr_number)) 2024-12-17T23:28:37.6166438Z except Exception as e: 2024-12-17T23:28:37.6167024Z raise Exception( # noqa: TRY002 2024-12-17T23:28:37.6167880Z f"issue with pull request {pr_number} from repo {repository}" 2024-12-17T23:28:37.6168554Z ) from e 2024-12-17T23:28:37.6169075Z return pull.user.login 2024-12-17T23:28:37.6169905Z # In all other cases, return the original input username 2024-12-17T23:28:37.6170567Z return username 2024-12-17T23:28:37.6170866Z 2024-12-17T23:28:37.6170873Z 2024-12-17T23:28:37.6171109Z def is_exception_branch(branch: str) -> bool: 2024-12-17T23:28:37.6171749Z """ 2024-12-17T23:28:37.6172469Z Branches that get opted out of experiments by default, until they're explicitly enabled. 2024-12-17T23:28:37.6173257Z """ 2024-12-17T23:28:37.6173909Z return branch.split("/")[0] in {"main", "nightly", "release", "landchecks"} 2024-12-17T23:28:37.6174475Z 2024-12-17T23:28:37.6174482Z 2024-12-17T23:28:37.6174731Z def load_yaml(yaml_text: str) -> Any: 2024-12-17T23:28:37.6175253Z try: 2024-12-17T23:28:37.6175756Z data = yaml.safe_load(yaml_text) 2024-12-17T23:28:37.6176361Z return data 2024-12-17T23:28:37.6176796Z except yaml.YAMLError: 2024-12-17T23:28:37.6177383Z log.exception("Error loading YAML") 2024-12-17T23:28:37.6177993Z raise 2024-12-17T23:28:37.6178228Z 2024-12-17T23:28:37.6178234Z 2024-12-17T23:28:37.6178650Z def extract_settings_user_opt_in_from_text(rollout_state: str) -> Tuple[str, str]: 2024-12-17T23:28:37.6179493Z """ 2024-12-17T23:28:37.6180181Z Extracts the text with settings, if any, and the opted in users from the rollout state. 2024-12-17T23:28:37.6180777Z 2024-12-17T23:28:37.6181171Z If the issue body contains "---" then the text above that is the settings 2024-12-17T23:28:37.6181995Z and the text below is the list of opted in users. 2024-12-17T23:28:37.6182454Z 2024-12-17T23:28:37.6182833Z If it doesn't contain "---" then the settings are empty and the rest is the users. 2024-12-17T23:28:37.6183737Z """ 2024-12-17T23:28:37.6184259Z rollout_state_parts = rollout_state.split("---") 2024-12-17T23:28:37.6184923Z if len(rollout_state_parts) >= 2: 2024-12-17T23:28:37.6185892Z return rollout_state_parts[0], rollout_state_parts[1] 2024-12-17T23:28:37.6186575Z else: 2024-12-17T23:28:37.6187049Z return "", rollout_state 2024-12-17T23:28:37.6187371Z 2024-12-17T23:28:37.6187377Z 2024-12-17T23:28:37.6187646Z class UserOptins(Dict[str, List[str]]): 2024-12-17T23:28:37.6188217Z """ 2024-12-17T23:28:37.6188809Z Dictionary of users with a list of features they have opted into 2024-12-17T23:28:37.6189524Z """ 2024-12-17T23:28:37.6189718Z 2024-12-17T23:28:37.6189724Z 2024-12-17T23:28:37.6190131Z def parse_user_opt_in_from_text(user_optin_text: str) -> UserOptins: 2024-12-17T23:28:37.6190867Z """ 2024-12-17T23:28:37.6191637Z 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.6192298Z 2024-12-17T23:28:37.6193020Z 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.6194019Z - Example line: "@User1,lf,split_build" 2024-12-17T23:28:37.6194760Z - A "#" prefix indicates the user is opted out of all experiments 2024-12-17T23:28:37.6195225Z 2024-12-17T23:28:37.6195231Z 2024-12-17T23:28:37.6195520Z """ 2024-12-17T23:28:37.6195944Z optins = UserOptins() 2024-12-17T23:28:37.6196492Z for user in user_optin_text.split("\n"): 2024-12-17T23:28:37.6197178Z user = user.strip("\r\n\t -") 2024-12-17T23:28:37.6197762Z if not user or not user.startswith("@"): 2024-12-17T23:28:37.6198360Z # Not a valid user. Skip 2024-12-17T23:28:37.6198964Z continue 2024-12-17T23:28:37.6199241Z 2024-12-17T23:28:37.6199422Z if user: 2024-12-17T23:28:37.6199911Z usr_name = user.split(",")[0].strip("@") 2024-12-17T23:28:37.6200732Z optins[usr_name] = [exp.strip(" ") for exp in user.split(",")[1:]] 2024-12-17T23:28:37.6201222Z 2024-12-17T23:28:37.6201437Z return optins 2024-12-17T23:28:37.6201689Z 2024-12-17T23:28:37.6201695Z 2024-12-17T23:28:37.6201989Z def is_valid_experiment_name(experiment_name: str) -> bool: 2024-12-17T23:28:37.6202872Z """ 2024-12-17T23:28:37.6203362Z Check if the experiment name is valid. 2024-12-17T23:28:37.6203899Z A valid name: 2024-12-17T23:28:37.6204681Z - Contains only alphanumeric characters and the special characters "_" & "-" 2024-12-17T23:28:37.6205655Z - The special characters "_" & "-" shouldn't be the first or last characters 2024-12-17T23:28:37.6206371Z - Cannot contain spaces 2024-12-17T23:28:37.6206967Z """ 2024-12-17T23:28:37.6207179Z 2024-12-17T23:28:37.6207489Z valid_char_regex = r"^[a-zA-Z0-9]([\w-]*[a-zA-Z0-9])?$" 2024-12-17T23:28:37.6208207Z valid = bool(re.match(valid_char_regex, experiment_name)) 2024-12-17T23:28:37.6208735Z 2024-12-17T23:28:37.6208933Z if valid: 2024-12-17T23:28:37.6209381Z return True 2024-12-17T23:28:37.6209630Z 2024-12-17T23:28:37.6209828Z log.error( 2024-12-17T23:28:37.6211338Z 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.6212857Z ) 2024-12-17T23:28:37.6213281Z return False 2024-12-17T23:28:37.6213592Z 2024-12-17T23:28:37.6213599Z 2024-12-17T23:28:37.6213939Z def parse_settings_from_text(settings_text: str) -> Settings: 2024-12-17T23:28:37.6214607Z """ 2024-12-17T23:28:37.6215232Z Parse the experiments from the issue body into a list of ExperimentSettings 2024-12-17T23:28:37.6216031Z """ 2024-12-17T23:28:37.6216457Z try: 2024-12-17T23:28:37.6216867Z if settings_text: 2024-12-17T23:28:37.6217665Z # 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.6218673Z # for easy reading 2024-12-17T23:28:37.6219480Z # Note: Using ascii for the backtick so that the cat step in _runner-determinator.yml doesn't choke on 2024-12-17T23:28:37.6220450Z # the backtick character in shell commands. 2024-12-17T23:28:37.6221118Z backtick = chr(96) # backtick character 2024-12-17T23:28:37.6221802Z settings_text = settings_text.strip(f"\r\n\t{backtick} ") 2024-12-17T23:28:37.6222551Z settings = load_yaml(settings_text) 2024-12-17T23:28:37.6222978Z 2024-12-17T23:28:37.6223378Z # For now we just load experiments. We can expand this if/when we add more settings 2024-12-17T23:28:37.6224145Z experiments = {} 2024-12-17T23:28:37.6224515Z 2024-12-17T23:28:37.6224940Z for exp_name, exp_settings in settings.get(SETTING_EXPERIMENTS).items(): 2024-12-17T23:28:37.6226294Z if not is_valid_experiment_name(exp_name): 2024-12-17T23:28:37.6227398Z # 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.6228635Z continue 2024-12-17T23:28:37.6228967Z 2024-12-17T23:28:37.6229188Z valid_settings = {} 2024-12-17T23:28:37.6229741Z for setting in exp_settings: 2024-12-17T23:28:37.6230453Z if setting not in Experiment._fields: 2024-12-17T23:28:37.6231022Z log.warning( 2024-12-17T23:28:37.6231752Z f"Unexpected setting in experiment: {setting} = {exp_settings[setting]}" 2024-12-17T23:28:37.6232606Z ) 2024-12-17T23:28:37.6233095Z else: 2024-12-17T23:28:37.6233606Z valid_settings[setting] = exp_settings[setting] 2024-12-17T23:28:37.6234160Z 2024-12-17T23:28:37.6234454Z experiments[exp_name] = Experiment(**valid_settings) 2024-12-17T23:28:37.6235124Z return Settings(experiments) 2024-12-17T23:28:37.6235478Z 2024-12-17T23:28:37.6235682Z except Exception: 2024-12-17T23:28:37.6236294Z log.exception("Failed to parse settings") 2024-12-17T23:28:37.6236685Z 2024-12-17T23:28:37.6237090Z return Settings() 2024-12-17T23:28:37.6237388Z 2024-12-17T23:28:37.6237394Z 2024-12-17T23:28:37.6237641Z def parse_settings(rollout_state: str) -> Settings: 2024-12-17T23:28:37.6238351Z """ 2024-12-17T23:28:37.6238853Z Parse settings, if any, from the rollout state. 2024-12-17T23:28:37.6239264Z 2024-12-17T23:28:37.6239699Z If the issue body contains "---" then the text above that is the settings 2024-12-17T23:28:37.6240477Z and the text below is the list of opted in users. 2024-12-17T23:28:37.6240928Z 2024-12-17T23:28:37.6241331Z If it doesn't contain "---" then the settings are empty and the default values are used. 2024-12-17T23:28:37.6242155Z """ 2024-12-17T23:28:37.6242761Z settings_text, _ = extract_settings_user_opt_in_from_text(rollout_state) 2024-12-17T23:28:37.6243576Z return parse_settings_from_text(settings_text) 2024-12-17T23:28:37.6243977Z 2024-12-17T23:28:37.6243984Z 2024-12-17T23:28:37.6244329Z def parse_users(rollout_state: str) -> UserOptins: 2024-12-17T23:28:37.6244917Z """ 2024-12-17T23:28:37.6245380Z Parse users from the rollout state. 2024-12-17T23:28:37.6245735Z 2024-12-17T23:28:37.6245996Z """ 2024-12-17T23:28:37.6246551Z _, users_text = extract_settings_user_opt_in_from_text(rollout_state) 2024-12-17T23:28:37.6247358Z return parse_user_opt_in_from_text(users_text) 2024-12-17T23:28:37.6247779Z 2024-12-17T23:28:37.6247786Z 2024-12-17T23:28:37.6248264Z def is_user_opted_in(user: str, user_optins: UserOptins, experiment_name: str) -> bool: 2024-12-17T23:28:37.6249070Z """ 2024-12-17T23:28:37.6249496Z Check if a user is opted into an experiment 2024-12-17T23:28:37.6250306Z """ 2024-12-17T23:28:37.6250850Z return experiment_name in user_optins.get(user, []) 2024-12-17T23:28:37.6251269Z 2024-12-17T23:28:37.6251275Z 2024-12-17T23:28:37.6251696Z def is_user_opted_out(user: str, user_optins: UserOptins, experiment_name: str) -> bool: 2024-12-17T23:28:37.6252517Z """ 2024-12-17T23:28:37.6253069Z Check if a user explicitly opted out of an experiment 2024-12-17T23:28:37.6253660Z """ 2024-12-17T23:28:37.6254270Z # if the experiment is prefixed with a "-", then it's an opt-out 2024-12-17T23:28:37.6255007Z experiment_optout = "-" + experiment_name 2024-12-17T23:28:37.6255661Z if experiment_optout not in user_optins.get(user, []): 2024-12-17T23:28:37.6256364Z return False 2024-12-17T23:28:37.6256645Z 2024-12-17T23:28:37.6256955Z if is_user_opted_in(user, user_optins, experiment_name): 2024-12-17T23:28:37.6257572Z log.warning( 2024-12-17T23:28:37.6258461Z f"User {user} is opted into experiment {experiment_name}, but also opted out of it. Defaulting to opting out" 2024-12-17T23:28:37.6259389Z ) 2024-12-17T23:28:37.6259605Z 2024-12-17T23:28:37.6259837Z return True 2024-12-17T23:28:37.6260059Z 2024-12-17T23:28:37.6260065Z 2024-12-17T23:28:37.6260318Z def get_runner_prefix( 2024-12-17T23:28:37.6260826Z rollout_state: str, 2024-12-17T23:28:37.6261359Z workflow_requestors: Iterable[str], 2024-12-17T23:28:37.6261937Z branch: str, 2024-12-17T23:28:37.6262502Z eligible_experiments: FrozenSet[str] = frozenset(), 2024-12-17T23:28:37.6263149Z is_canary: bool = False, 2024-12-17T23:28:37.6263672Z ) -> str: 2024-12-17T23:28:37.6264159Z settings = parse_settings(rollout_state) 2024-12-17T23:28:37.6264794Z user_optins = parse_users(rollout_state) 2024-12-17T23:28:37.6265150Z 2024-12-17T23:28:37.6265706Z fleet_prefix = "" 2024-12-17T23:28:37.6266286Z prefixes = [] 2024-12-17T23:28:37.6266987Z for experiment_name, experiment_settings in settings.experiments.items(): 2024-12-17T23:28:37.6267977Z if not experiment_settings.all_branches and is_exception_branch(branch): 2024-12-17T23:28:37.6268749Z log.info( 2024-12-17T23:28:37.6269483Z f"Branch {branch} is an exception branch. Not enabling experiment {experiment_name}." 2024-12-17T23:28:37.6270374Z ) 2024-12-17T23:28:37.6271010Z continue 2024-12-17T23:28:37.6271293Z 2024-12-17T23:28:37.6271591Z if eligible_experiments: 2024-12-17T23:28:37.6272198Z if experiment_name not in eligible_experiments: 2024-12-17T23:28:37.6272874Z exp_list = ", ".join(eligible_experiments) 2024-12-17T23:28:37.6273521Z log.info( 2024-12-17T23:28:37.6274371Z f"Skipping experiment '{experiment_name}', as it is not in the eligible_experiments list: {exp_list}" 2024-12-17T23:28:37.6275200Z ) 2024-12-17T23:28:37.6275700Z continue 2024-12-17T23:28:37.6276259Z elif not experiment_settings.default: 2024-12-17T23:28:37.6276811Z log.info( 2024-12-17T23:28:37.6277552Z f"Skipping experiment '{experiment_name}', as it is not a default experiment" 2024-12-17T23:28:37.6278366Z ) 2024-12-17T23:28:37.6278767Z continue 2024-12-17T23:28:37.6279041Z 2024-12-17T23:28:37.6279417Z # Is any workflow_requestor opted out to this experiment? 2024-12-17T23:28:37.6280089Z opted_out_users = [ 2024-12-17T23:28:37.6280565Z requestor 2024-12-17T23:28:37.6281141Z for requestor in workflow_requestors 2024-12-17T23:28:37.6281882Z if is_user_opted_out(requestor, user_optins, experiment_name) 2024-12-17T23:28:37.6282527Z ] 2024-12-17T23:28:37.6282786Z 2024-12-17T23:28:37.6283043Z if opted_out_users: 2024-12-17T23:28:37.6283567Z log.info( 2024-12-17T23:28:37.6284194Z f"{', '.join(opted_out_users)} have opted out of experiment {experiment_name}." 2024-12-17T23:28:37.6284990Z ) 2024-12-17T23:28:37.6285623Z continue 2024-12-17T23:28:37.6285884Z 2024-12-17T23:28:37.6286183Z # Is any workflow_requestor opted in to this experiment? 2024-12-17T23:28:37.6286908Z opted_in_users = [ 2024-12-17T23:28:37.6287433Z requestor 2024-12-17T23:28:37.6287925Z for requestor in workflow_requestors 2024-12-17T23:28:37.6288689Z if is_user_opted_in(requestor, user_optins, experiment_name) 2024-12-17T23:28:37.6289370Z ] 2024-12-17T23:28:37.6289602Z 2024-12-17T23:28:37.6289784Z enabled = False 2024-12-17T23:28:37.6290323Z if opted_in_users: 2024-12-17T23:28:37.6290855Z log.info( 2024-12-17T23:28:37.6291467Z f"{', '.join(opted_in_users)} have opted into experiment {experiment_name}." 2024-12-17T23:28:37.6292244Z ) 2024-12-17T23:28:37.6292722Z enabled = True 2024-12-17T23:28:37.6293011Z 2024-12-17T23:28:37.6293232Z elif experiment_settings.rollout_perc: 2024-12-17T23:28:37.6294138Z # If no user is opted in, then we randomly enable the experiment based on the rollout percentage 2024-12-17T23:28:37.6295116Z if random.uniform(0, 100) <= experiment_settings.rollout_perc: 2024-12-17T23:28:37.6295801Z log.info( 2024-12-17T23:28:37.6296704Z f"Based on rollout percentage of {experiment_settings.rollout_perc}%, enabling experiment {experiment_name}." 2024-12-17T23:28:37.6297679Z ) 2024-12-17T23:28:37.6298132Z enabled = True 2024-12-17T23:28:37.6298534Z 2024-12-17T23:28:37.6298780Z if enabled: 2024-12-17T23:28:37.6299300Z label = experiment_name 2024-12-17T23:28:37.6299908Z if experiment_name == LF_FLEET_EXPERIMENT: 2024-12-17T23:28:37.6300775Z # We give some special treatment to the "lf" experiment since determines the fleet we use 2024-12-17T23:28:37.6301714Z # - If it's enabled, then we always list it's prefix first 2024-12-17T23:28:37.6302509Z # - If we're in the canary branch, then we append ".c" to the lf prefix 2024-12-17T23:28:37.6303283Z if is_canary: 2024-12-17T23:28:37.6303791Z label += CANARY_FLEET_SUFFIX 2024-12-17T23:28:37.6304381Z fleet_prefix = label 2024-12-17T23:28:37.6305122Z else: 2024-12-17T23:28:37.6305892Z prefixes.append(label) 2024-12-17T23:28:37.6306277Z 2024-12-17T23:28:37.6306494Z if len(prefixes) > 1: 2024-12-17T23:28:37.6307068Z log.error( 2024-12-17T23:28:37.6308081Z 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.6309230Z ) 2024-12-17T23:28:37.6309734Z prefixes = prefixes[:1] 2024-12-17T23:28:37.6310051Z 2024-12-17T23:28:37.6310250Z # Fleet always comes first 2024-12-17T23:28:37.6310782Z if fleet_prefix: 2024-12-17T23:28:37.6311353Z prefixes.insert(0, fleet_prefix) 2024-12-17T23:28:37.6311713Z 2024-12-17T23:28:37.6311966Z return ".".join(prefixes) + "." if prefixes else "" 2024-12-17T23:28:37.6312431Z 2024-12-17T23:28:37.6312437Z 2024-12-17T23:28:37.6312892Z def get_rollout_state_from_issue(github_token: str, repo: str, issue_num: int) -> str: 2024-12-17T23:28:37.6313761Z """ 2024-12-17T23:28:37.6314354Z Gets the first comment of the issue, which contains the desired rollout state. 2024-12-17T23:28:37.6314949Z 2024-12-17T23:28:37.6315329Z The default issue we use - https://github.com/pytorch/test-infra/issues/5132 2024-12-17T23:28:37.6316130Z """ 2024-12-17T23:28:37.6316597Z gh = get_gh_client(github_token) 2024-12-17T23:28:37.6317144Z issue = get_issue(gh, repo, issue_num) 2024-12-17T23:28:37.6317888Z return str(issue.get_comments()[0].body.strip("\n\t ")) 2024-12-17T23:28:37.6318324Z 2024-12-17T23:28:37.6318331Z 2024-12-17T23:28:37.6318776Z def download_json(url: str, headers: Dict[str, str], num_retries: int = 3) -> Any: 2024-12-17T23:28:37.6319695Z for _ in range(num_retries): 2024-12-17T23:28:37.6320328Z try: 2024-12-17T23:28:37.6320813Z req = Request(url=url, headers=headers) 2024-12-17T23:28:37.6321476Z content = urlopen(req, timeout=5).read().decode("utf-8") 2024-12-17T23:28:37.6322260Z return json.loads(content) 2024-12-17T23:28:37.6322832Z except Exception as e: 2024-12-17T23:28:37.6323378Z log.warning(f"Could not download {url}: {e}") 2024-12-17T23:28:37.6323877Z 2024-12-17T23:28:37.6324286Z log.warning(f"All {num_retries} retries exhausted, downloading {url} failed") 2024-12-17T23:28:37.6325033Z return {} 2024-12-17T23:28:37.6325267Z 2024-12-17T23:28:37.6325273Z 2024-12-17T23:28:37.6325484Z @lru_cache(maxsize=None) 2024-12-17T23:28:37.6326266Z def get_pr_info(github_repo: str, github_token: str, pr_number: int) -> Dict[str, Any]: 2024-12-17T23:28:37.6327047Z """ 2024-12-17T23:28:37.6327479Z Dynamically get PR information 2024-12-17T23:28:37.6328132Z """ 2024-12-17T23:28:37.6328676Z github_api = f"https://api.github.com/repos/{github_repo}" 2024-12-17T23:28:37.6329338Z headers = { 2024-12-17T23:28:37.6329890Z "Accept": "application/vnd.github.v3+json", 2024-12-17T23:28:37.6330536Z "Authorization": f"token {github_token}", 2024-12-17T23:28:37.6331113Z } 2024-12-17T23:28:37.6331633Z json_response: Dict[str, Any] = download_json( 2024-12-17T23:28:37.6332285Z url=f"{github_api}/issues/{pr_number}", 2024-12-17T23:28:37.6332869Z headers=headers, 2024-12-17T23:28:37.6333397Z ) 2024-12-17T23:28:37.6333641Z 2024-12-17T23:28:37.6333832Z if not json_response: 2024-12-17T23:28:37.6334435Z log.warning(f"Failed to get the labels for #{pr_number}") 2024-12-17T23:28:37.6335130Z return {} 2024-12-17T23:28:37.6335408Z 2024-12-17T23:28:37.6335599Z return json_response 2024-12-17T23:28:37.6335889Z 2024-12-17T23:28:37.6335895Z 2024-12-17T23:28:37.6336317Z def get_labels(github_repo: str, github_token: str, pr_number: int) -> Set[str]: 2024-12-17T23:28:37.6337110Z """ 2024-12-17T23:28:37.6337696Z Dynamically get the latest list of labels from the pull request 2024-12-17T23:28:37.6338363Z """ 2024-12-17T23:28:37.6339091Z pr_info = get_pr_info(github_repo, github_token, pr_number) 2024-12-17T23:28:37.6339781Z return { 2024-12-17T23:28:37.6340386Z label.get("name") for label in pr_info.get("labels", []) if label.get("name") 2024-12-17T23:28:37.6341164Z } 2024-12-17T23:28:37.6341424Z 2024-12-17T23:28:37.6341431Z 2024-12-17T23:28:37.6341615Z def main() -> None: 2024-12-17T23:28:37.6342076Z args = parse_args() 2024-12-17T23:28:37.6342419Z 2024-12-17T23:28:37.6342715Z runner_label_prefix = DEFAULT_LABEL_PREFIX 2024-12-17T23:28:37.6343097Z 2024-12-17T23:28:37.6343297Z # Check if the PR is opt-out 2024-12-17T23:28:37.6343820Z if args.pr_number: 2024-12-17T23:28:37.6344604Z labels = get_labels(args.github_repo, args.github_token, int(args.pr_number)) 2024-12-17T23:28:37.6345640Z if OPT_OUT_LABEL in labels: 2024-12-17T23:28:37.6346203Z log.info( 2024-12-17T23:28:37.6347051Z f"Opt-out runner determinator because #{args.pr_number} has {OPT_OUT_LABEL} label" 2024-12-17T23:28:37.6347813Z ) 2024-12-17T23:28:37.6348390Z set_github_output(GH_OUTPUT_KEY_LABEL_TYPE, runner_label_prefix) 2024-12-17T23:28:37.6349198Z sys.exit() 2024-12-17T23:28:37.6349470Z 2024-12-17T23:28:37.6349641Z try: 2024-12-17T23:28:37.6350107Z rollout_state = get_rollout_state_from_issue( 2024-12-17T23:28:37.6350938Z args.github_token, args.github_issue_repo, args.github_issue 2024-12-17T23:28:37.6351571Z ) 2024-12-17T23:28:37.6351820Z 2024-12-17T23:28:37.6352018Z username = get_potential_pr_author( 2024-12-17T23:28:37.6352697Z args.github_token, 2024-12-17T23:28:37.6353193Z args.github_repo, 2024-12-17T23:28:37.6353911Z args.github_actor, 2024-12-17T23:28:37.6354527Z args.github_ref_type, 2024-12-17T23:28:37.6355031Z args.github_branch, 2024-12-17T23:28:37.6355546Z ) 2024-12-17T23:28:37.6355826Z 2024-12-17T23:28:37.6356184Z is_canary = args.github_repo == "pytorch/pytorch-canary" 2024-12-17T23:28:37.6356628Z 2024-12-17T23:28:37.6356910Z runner_label_prefix = get_runner_prefix( 2024-12-17T23:28:37.6357453Z rollout_state, 2024-12-17T23:28:37.6358065Z (args.github_issue_owner, username), 2024-12-17T23:28:37.6358673Z args.github_branch, 2024-12-17T23:28:37.6359160Z args.eligible_experiments, 2024-12-17T23:28:37.6359791Z is_canary, 2024-12-17T23:28:37.6360272Z ) 2024-12-17T23:28:37.6360496Z 2024-12-17T23:28:37.6360686Z except Exception as e: 2024-12-17T23:28:37.6361253Z log.error( 2024-12-17T23:28:37.6361966Z f"Failed to get issue. Defaulting to Meta runners and no experiments. Exception: {e}" 2024-12-17T23:28:37.6362715Z ) 2024-12-17T23:28:37.6363061Z 2024-12-17T23:28:37.6363396Z set_github_output(GH_OUTPUT_KEY_LABEL_TYPE, runner_label_prefix) 2024-12-17T23:28:37.6363898Z 2024-12-17T23:28:37.6363904Z 2024-12-17T23:28:37.6364133Z if __name__ == "__main__": 2024-12-17T23:28:37.6364575Z main() 2024-12-17T23:28:37.6364916Z 2024-12-17T23:28:37.6456995Z ##[group]Run python3 -m pip install urllib3==1.26.18 PyGithub==2.3.0 2024-12-17T23:28:37.6457999Z python3 -m pip install urllib3==1.26.18 PyGithub==2.3.0 2024-12-17T23:28:37.6514346Z shell: /usr/bin/bash -e {0} 2024-12-17T23:28:37.6515015Z env: 2024-12-17T23:28:37.6515690Z GITHUB_TOKEN: *** 2024-12-17T23:28:37.6516114Z ISSUE_NUMBER: 5132 2024-12-17T23:28:37.6516706Z TRIGGERING_ACTOR: malfet 2024-12-17T23:28:37.6517225Z ISSUE_OWNER: 2024-12-17T23:28:37.6517629Z CHECK_EXPERIMENTS: 2024-12-17T23:28:37.6518185Z PR_NUMBER: 2024-12-17T23:28:37.6518635Z ##[endgroup] 2024-12-17T23:28:38.0935308Z Defaulting to user installation because normal site-packages is not writeable 2024-12-17T23:28:38.4303654Z Collecting urllib3==1.26.18 2024-12-17T23:28:38.4783555Z Downloading urllib3-1.26.18-py2.py3-none-any.whl (143 kB) 2024-12-17T23:28:38.5116101Z ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 143.8/143.8 KB 6.1 MB/s eta 0:00:00 2024-12-17T23:28:38.5356235Z Collecting PyGithub==2.3.0 2024-12-17T23:28:38.5405525Z Downloading PyGithub-2.3.0-py3-none-any.whl (354 kB) 2024-12-17T23:28:38.5496315Z ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 354.4/354.4 KB 48.5 MB/s eta 0:00:00 2024-12-17T23:28:38.5944667Z Collecting typing-extensions>=4.0.0 2024-12-17T23:28:38.5972849Z Downloading typing_extensions-4.12.2-py3-none-any.whl (37 kB) 2024-12-17T23:28:38.6251102Z Collecting pyjwt[crypto]>=2.4.0 2024-12-17T23:28:38.6279107Z Downloading PyJWT-2.10.1-py3-none-any.whl (22 kB) 2024-12-17T23:28:38.6623871Z Collecting pynacl>=1.4.0 2024-12-17T23:28:38.6656417Z 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:38.6788894Z ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 856.7/856.7 KB 74.7 MB/s eta 0:00:00 2024-12-17T23:28:38.7012047Z Collecting Deprecated 2024-12-17T23:28:38.7042584Z Downloading Deprecated-1.2.15-py2.py3-none-any.whl (9.9 kB) 2024-12-17T23:28:38.7072035Z 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:38.7233997Z 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:38.9421299Z Collecting cffi>=1.4.1 2024-12-17T23:28:38.9470565Z Downloading cffi-1.17.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (446 kB) 2024-12-17T23:28:38.9560419Z ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 446.2/446.2 KB 63.7 MB/s eta 0:00:00 2024-12-17T23:28:39.1450292Z Collecting wrapt<2,>=1.10 2024-12-17T23:28:39.1488685Z 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:39.1538496Z ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 82.7/82.7 KB 29.8 MB/s eta 0:00:00 2024-12-17T23:28:39.1781510Z Collecting pycparser 2024-12-17T23:28:39.1876816Z Downloading pycparser-2.22-py3-none-any.whl (117 kB) 2024-12-17T23:28:39.1940056Z ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 117.6/117.6 KB 30.7 MB/s eta 0:00:00 2024-12-17T23:28:39.3811725Z Installing collected packages: wrapt, urllib3, typing-extensions, pyjwt, pycparser, Deprecated, cffi, pynacl, PyGithub 2024-12-17T23:28:39.8653854Z 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:39.9313663Z ##[group]Run curr_branch="release/2.6" 2024-12-17T23:28:39.9314226Z curr_branch="release/2.6" 2024-12-17T23:28:39.9314639Z curr_ref_type="branch" 2024-12-17T23:28:39.9315145Z echo "Current branch is '$curr_branch'" 2024-12-17T23:28:39.9315546Z  2024-12-17T23:28:39.9315875Z python3 runner_determinator.py \ 2024-12-17T23:28:39.9316353Z  --github-token "$GITHUB_TOKEN" \ 2024-12-17T23:28:39.9316770Z  --github-issue "$ISSUE_NUMBER" \ 2024-12-17T23:28:39.9317173Z  --github-branch "$curr_branch" \ 2024-12-17T23:28:39.9317618Z  --github-actor "$TRIGGERING_ACTOR" \ 2024-12-17T23:28:39.9318038Z  --github-issue-owner "$ISSUE_OWNER" \ 2024-12-17T23:28:39.9318462Z  --github-ref-type "$curr_ref_type" \ 2024-12-17T23:28:39.9318927Z  --github-repo "$GITHUB_REPOSITORY" \ 2024-12-17T23:28:39.9319390Z  --eligible-experiments "$CHECK_EXPERIMENTS" \ 2024-12-17T23:28:39.9320040Z  --pr-number "${PR_NUMBER}" 2024-12-17T23:28:39.9377864Z shell: /usr/bin/bash -e {0} 2024-12-17T23:28:39.9378332Z env: 2024-12-17T23:28:39.9379100Z GITHUB_TOKEN: *** 2024-12-17T23:28:39.9379452Z ISSUE_NUMBER: 5132 2024-12-17T23:28:39.9379862Z TRIGGERING_ACTOR: malfet 2024-12-17T23:28:39.9380209Z ISSUE_OWNER: 2024-12-17T23:28:39.9380504Z CHECK_EXPERIMENTS: 2024-12-17T23:28:39.9380909Z PR_NUMBER: 2024-12-17T23:28:39.9381205Z ##[endgroup] 2024-12-17T23:28:39.9457420Z Current branch is 'release/2.6' 2024-12-17T23:28:41.2633703Z INFO : Based on rollout percentage of 95%, enabling experiment lf. 2024-12-17T23:28:41.2635084Z INFO : Skipping experiment 'awsa100', as it is not a default experiment 2024-12-17T23:28:41.2635747Z INFO : Setting output: label-type='lf.' 2024-12-17T23:28:41.2913220Z Evaluate and set job outputs 2024-12-17T23:28:41.2920072Z Set output 'label-type' 2024-12-17T23:28:41.2922136Z Cleaning up orphan processes