2025-01-24T00:45:43.7994707Z Current runner version: '2.321.0' 2025-01-24T00:45:43.8026919Z ##[group]Operating System 2025-01-24T00:45:43.8027728Z Ubuntu 2025-01-24T00:45:43.8028245Z 24.04.1 2025-01-24T00:45:43.8028708Z LTS 2025-01-24T00:45:43.8029227Z ##[endgroup] 2025-01-24T00:45:43.8029779Z ##[group]Runner Image 2025-01-24T00:45:43.8030295Z Image: ubuntu-24.04 2025-01-24T00:45:43.8030836Z Version: 20250120.5.0 2025-01-24T00:45:43.8032123Z Included Software: https://github.com/actions/runner-images/blob/ubuntu24/20250120.5/images/ubuntu/Ubuntu2404-Readme.md 2025-01-24T00:45:43.8033474Z Image Release: https://github.com/actions/runner-images/releases/tag/ubuntu24%2F20250120.5 2025-01-24T00:45:43.8034412Z ##[endgroup] 2025-01-24T00:45:43.8034957Z ##[group]Runner Image Provisioner 2025-01-24T00:45:43.8035511Z 2.0.417.1 2025-01-24T00:45:43.8036012Z ##[endgroup] 2025-01-24T00:45:43.8038080Z ##[group]GITHUB_TOKEN Permissions 2025-01-24T00:45:43.8040155Z Actions: read 2025-01-24T00:45:43.8040988Z Attestations: read 2025-01-24T00:45:43.8041611Z Checks: read 2025-01-24T00:45:43.8042453Z Contents: read 2025-01-24T00:45:43.8042947Z Deployments: read 2025-01-24T00:45:43.8043500Z Discussions: read 2025-01-24T00:45:43.8044011Z Issues: read 2025-01-24T00:45:43.8044472Z Metadata: read 2025-01-24T00:45:43.8044984Z Packages: read 2025-01-24T00:45:43.8045491Z Pages: read 2025-01-24T00:45:43.8045952Z PullRequests: read 2025-01-24T00:45:43.8046505Z RepositoryProjects: read 2025-01-24T00:45:43.8047071Z SecurityEvents: read 2025-01-24T00:45:43.8047563Z Statuses: read 2025-01-24T00:45:43.8048147Z ##[endgroup] 2025-01-24T00:45:43.8051529Z Secret source: Actions 2025-01-24T00:45:43.8052642Z Prepare workflow directory 2025-01-24T00:45:43.8533857Z Prepare all required actions 2025-01-24T00:45:43.8588432Z Uses: pytorch/pytorch/.github/workflows/_runner-determinator.yml@refs/heads/main (b2c89bc115123aea8e075e882ee121537ec92f89) 2025-01-24T00:45:43.8593901Z ##[group] Inputs 2025-01-24T00:45:43.8594540Z check_experiments: 2025-01-24T00:45:43.8595118Z triggering_actor: pytorch-bot[bot] 2025-01-24T00:45:43.8595814Z issue_owner: 2025-01-24T00:45:43.8596377Z curr_branch: ciflow/inductor/145539 2025-01-24T00:45:43.8596982Z curr_ref_type: tag 2025-01-24T00:45:43.8597553Z issue_number: 5132 2025-01-24T00:45:43.8598098Z ##[endgroup] 2025-01-24T00:45:43.8598724Z Complete job name: unit-test / get-label-type / runner-determinator 2025-01-24T00:45:43.9322276Z ##[group]Run cat < runner_determinator.py 2025-01-24T00:45:43.9323934Z cat < runner_determinator.py 2025-01-24T00:45:43.9324491Z # flake8: noqa: G004 2025-01-24T00:45:43.9324947Z  2025-01-24T00:45:43.9325582Z # Note: Copies of this script in runner_determinator.py and _runner-determinator.yml 2025-01-24T00:45:43.9326527Z # must be kept in sync. You can do it easily by running the following command: 2025-01-24T00:45:43.9327339Z # python .github/scripts/update_runner_determinator.py 2025-01-24T00:45:43.9327943Z  2025-01-24T00:45:43.9328309Z """ 2025-01-24T00:45:43.9328916Z This runner determinator is used to determine which set of runners to run a 2025-01-24T00:45:43.9329803Z GitHub job on. It uses the first comment of a GitHub issue (by default 2025-01-24T00:45:43.9330752Z https://github.com/pytorch/test-infra/issues/5132) to define the configuration 2025-01-24T00:45:43.9331591Z of which runners should be used to run which job. 2025-01-24T00:45:43.9332343Z  2025-01-24T00:45:43.9332928Z The configuration has two parts, the settings and a list of opted-in users, 2025-01-24T00:45:43.9333825Z separated by a line containing "---". If the line is not present, the 2025-01-24T00:45:43.9334707Z settings are considered to be empty with only the second part, the user 2025-01-24T00:45:43.9335404Z list, defined. 2025-01-24T00:45:43.9335815Z  2025-01-24T00:45:43.9336381Z The first part is a YAML block that defines the rollout settings. This can be 2025-01-24T00:45:43.9337637Z used to define any settings that are needed to determine which runners to use. 2025-01-24T00:45:43.9338501Z It's fields are defined by the RolloutSettings class below. 2025-01-24T00:45:43.9339112Z  2025-01-24T00:45:43.9339695Z The second part is a list of users who are explicitly opted in to the LF fleet. 2025-01-24T00:45:43.9340578Z The user list is also a comma separated list of additional features or 2025-01-24T00:45:43.9341345Z experiments which the user could be opted in to. 2025-01-24T00:45:43.9342041Z  2025-01-24T00:45:43.9342448Z The user list has the following rules: 2025-01-24T00:45:43.9342954Z  2025-01-24T00:45:43.9343476Z - Users are GitHub usernames, which must start with the @ prefix 2025-01-24T00:45:43.9344322Z - Each user is also a comma-separated list of features/experiments to enable 2025-01-24T00:45:43.9345110Z - A "#" prefix opts the user out of all experiments 2025-01-24T00:45:43.9345654Z  2025-01-24T00:45:43.9346020Z Example config: 2025-01-24T00:45:43.9346538Z  # A list of experiments that can be opted into. 2025-01-24T00:45:43.9347243Z  # This defines the behavior they'll induce when opted into. 2025-01-24T00:45:43.9347896Z  # Expected syntax is: 2025-01-24T00:45:43.9348583Z  # [experiment_name]: # Name of the experiment. Also used for the label prefix. 2025-01-24T00:45:43.9349554Z  # rollout_perc: [int] # % of workflows to run with this experiment when users are not opted in. 2025-01-24T00:45:43.9350307Z  2025-01-24T00:45:43.9350681Z  experiments: 2025-01-24T00:45:43.9351105Z  lf: 2025-01-24T00:45:43.9351526Z  rollout_percent: 25 2025-01-24T00:45:43.9352286Z  all_branches: false 2025-01-24T00:45:43.9352790Z  default: true 2025-01-24T00:45:43.9353252Z  --- 2025-01-24T00:45:43.9353628Z  2025-01-24T00:45:43.9353982Z  # Opt-ins: 2025-01-24T00:45:43.9354625Z  # Users can opt into the LF fleet by adding their GitHub username to this list 2025-01-24T00:45:43.9355699Z  # and specifying experiments to enable in a comma-separated list. 2025-01-24T00:45:43.9356502Z  # To always opt out of an experiment, prefix it with a "-". 2025-01-24T00:45:43.9357185Z  # Experiments should be from the above list. 2025-01-24T00:45:43.9357731Z  2025-01-24T00:45:43.9358160Z  @User1,-lf,split_build 2025-01-24T00:45:43.9358634Z  @User2,lf 2025-01-24T00:45:43.9359066Z  @User3,split_build 2025-01-24T00:45:43.9359528Z """ 2025-01-24T00:45:43.9359887Z  2025-01-24T00:45:43.9360249Z import json 2025-01-24T00:45:43.9360658Z import logging 2025-01-24T00:45:43.9361086Z import os 2025-01-24T00:45:43.9361490Z import random 2025-01-24T00:45:43.9362101Z import re 2025-01-24T00:45:43.9362500Z import sys 2025-01-24T00:45:43.9362955Z from argparse import ArgumentParser 2025-01-24T00:45:43.9363508Z from functools import lru_cache 2025-01-24T00:45:43.9364045Z from logging import LogRecord 2025-01-24T00:45:43.9364776Z from typing import Any, Dict, FrozenSet, Iterable, List, NamedTuple, Set, Tuple 2025-01-24T00:45:43.9365604Z from urllib.request import Request, urlopen 2025-01-24T00:45:43.9366304Z  2025-01-24T00:45:43.9366890Z import yaml 2025-01-24T00:45:43.9367594Z from github import Auth, Github 2025-01-24T00:45:43.9368470Z from github.Issue import Issue 2025-01-24T00:45:43.9369315Z  2025-01-24T00:45:43.9369941Z  2025-01-24T00:45:43.9370695Z DEFAULT_LABEL_PREFIX = "" # use meta runners 2025-01-24T00:45:43.9372564Z WORKFLOW_LABEL_LF = "lf." # use runners from the linux foundation 2025-01-24T00:45:43.9374271Z WORKFLOW_LABEL_LF_CANARY = "lf.c." # use canary runners from the linux foundation 2025-01-24T00:45:43.9375607Z  2025-01-24T00:45:43.9376391Z GITHUB_OUTPUT = os.getenv("GITHUB_OUTPUT", "") 2025-01-24T00:45:43.9377466Z GH_OUTPUT_KEY_AMI = "runner-ami" 2025-01-24T00:45:43.9378425Z GH_OUTPUT_KEY_LABEL_TYPE = "label-type" 2025-01-24T00:45:43.9379464Z OPT_OUT_LABEL = "no-runner-experiments" 2025-01-24T00:45:43.9380380Z  2025-01-24T00:45:43.9381091Z SETTING_EXPERIMENTS = "experiments" 2025-01-24T00:45:43.9382254Z  2025-01-24T00:45:43.9382962Z LF_FLEET_EXPERIMENT = "lf" 2025-01-24T00:45:43.9383803Z CANARY_FLEET_SUFFIX = ".c" 2025-01-24T00:45:43.9384665Z  2025-01-24T00:45:43.9385289Z  2025-01-24T00:45:43.9385980Z class Experiment(NamedTuple): 2025-01-24T00:45:43.9386951Z  rollout_perc: float = ( 2025-01-24T00:45:43.9388170Z  0 # Percentage of workflows to experiment on when user is not opted-in. 2025-01-24T00:45:43.9389420Z  ) 2025-01-24T00:45:43.9390114Z  all_branches: bool = ( 2025-01-24T00:45:43.9391355Z  False # If True, the experiment is also enabled on the exception branches 2025-01-24T00:45:43.9392833Z  ) 2025-01-24T00:45:43.9393549Z  default: bool = ( 2025-01-24T00:45:43.9394760Z  True # If True, the experiment is enabled by default for all queries 2025-01-24T00:45:43.9396059Z  ) 2025-01-24T00:45:43.9396694Z  2025-01-24T00:45:43.9397319Z  # Add more fields as needed 2025-01-24T00:45:43.9398175Z  2025-01-24T00:45:43.9398750Z  2025-01-24T00:45:43.9399406Z class Settings(NamedTuple): 2025-01-24T00:45:43.9400294Z  """ 2025-01-24T00:45:43.9401215Z  Settings for the experiments that can be opted into. 2025-01-24T00:45:43.9402470Z  """ 2025-01-24T00:45:43.9403131Z  2025-01-24T00:45:43.9403845Z  experiments: Dict[str, Experiment] = {} 2025-01-24T00:45:43.9404787Z  2025-01-24T00:45:43.9405416Z  2025-01-24T00:45:43.9406397Z class ColorFormatter(logging.Formatter): 2025-01-24T00:45:43.9407621Z  """Color codes the log messages based on the log level""" 2025-01-24T00:45:43.9408686Z  2025-01-24T00:45:43.9409296Z  COLORS = { 2025-01-24T00:45:43.9410529Z  "WARNING": "\033[33m", # Yellow 2025-01-24T00:45:43.9412078Z  "ERROR": "\033[31m", # Red 2025-01-24T00:45:43.9413068Z  "CRITICAL": "\033[31m", # Red 2025-01-24T00:45:43.9414037Z  "INFO": "\033[0m", # Reset 2025-01-24T00:45:43.9415023Z  "DEBUG": "\033[0m", # Reset 2025-01-24T00:45:43.9415930Z  } 2025-01-24T00:45:43.9416563Z  2025-01-24T00:45:43.9417312Z  def format(self, record: LogRecord) -> str: 2025-01-24T00:45:43.9418671Z  log_color = self.COLORS.get(record.levelname, "\033[0m") # Default to reset 2025-01-24T00:45:43.9420238Z  record.msg = f"{log_color}{record.msg}\033[0m" 2025-01-24T00:45:43.9421382Z  return super().format(record) 2025-01-24T00:45:43.9422528Z  2025-01-24T00:45:43.9423178Z  2025-01-24T00:45:43.9423889Z handler = logging.StreamHandler() 2025-01-24T00:45:43.9425283Z handler.setFormatter(ColorFormatter(fmt="%(levelname)-8s: %(message)s")) 2025-01-24T00:45:43.9426618Z  2025-01-24T00:45:43.9427445Z log = logging.getLogger(os.path.basename(__file__)) 2025-01-24T00:45:43.9428514Z log.addHandler(handler) 2025-01-24T00:45:43.9429381Z log.setLevel(logging.INFO) 2025-01-24T00:45:43.9430586Z  2025-01-24T00:45:43.9431215Z  2025-01-24T00:45:43.9432246Z def set_github_output(key: str, value: str) -> None: 2025-01-24T00:45:43.9433293Z  """ 2025-01-24T00:45:43.9434243Z  Defines outputs of the github action that invokes this script 2025-01-24T00:45:43.9435495Z  """ 2025-01-24T00:45:43.9436258Z  if not GITHUB_OUTPUT: 2025-01-24T00:45:43.9438278Z  # See https://github.blog/changelog/2022-10-11-github-actions-deprecating-save-state-and-set-output-commands/ for deprecation notice 2025-01-24T00:45:43.9440396Z  log.warning( 2025-01-24T00:45:43.9442203Z  "No env var found for GITHUB_OUTPUT, you must be running this code locally. Falling back to the deprecated print method." 2025-01-24T00:45:43.9443945Z  ) 2025-01-24T00:45:43.9444769Z  print(f"::set-output name={key}::{value}") 2025-01-24T00:45:43.9445729Z  return 2025-01-24T00:45:43.9446429Z  2025-01-24T00:45:43.9447095Z  with open(GITHUB_OUTPUT, "a") as f: 2025-01-24T00:45:43.9448154Z  log.info(f"Setting output: {key}='{value}'") 2025-01-24T00:45:43.9449193Z  f.write(f"{key}={value}\n") 2025-01-24T00:45:43.9450038Z  2025-01-24T00:45:43.9450628Z  2025-01-24T00:45:43.9451503Z def _str_comma_separated_to_set(value: str) -> FrozenSet[str]: 2025-01-24T00:45:43.9452828Z  return frozenset( 2025-01-24T00:45:43.9453983Z  filter(lambda itm: itm != "", map(str.strip, value.strip(" \n\t").split(","))) 2025-01-24T00:45:43.9455213Z  ) 2025-01-24T00:45:43.9455814Z  2025-01-24T00:45:43.9456487Z  2025-01-24T00:45:43.9457096Z def parse_args() -> Any: 2025-01-24T00:45:43.9458199Z  parser = ArgumentParser("Get dynamic rollout settings") 2025-01-24T00:45:43.9459743Z  parser.add_argument("--github-token", type=str, required=True, help="GitHub token") 2025-01-24T00:45:43.9461120Z  parser.add_argument( 2025-01-24T00:45:43.9462232Z  "--github-issue-repo", 2025-01-24T00:45:43.9463026Z  type=str, 2025-01-24T00:45:43.9463482Z  required=False, 2025-01-24T00:45:43.9464177Z  default="pytorch/test-infra", 2025-01-24T00:45:43.9464759Z  help="GitHub repo to get the issue", 2025-01-24T00:45:43.9465314Z  ) 2025-01-24T00:45:43.9465706Z  parser.add_argument( 2025-01-24T00:45:43.9466192Z  "--github-repo", 2025-01-24T00:45:43.9466652Z  type=str, 2025-01-24T00:45:43.9467089Z  required=True, 2025-01-24T00:45:43.9467608Z  help="GitHub repo where CI is running", 2025-01-24T00:45:43.9468138Z  ) 2025-01-24T00:45:43.9468527Z  parser.add_argument( 2025-01-24T00:45:43.9469196Z  "--github-issue", type=int, required=True, help="GitHub issue number" 2025-01-24T00:45:43.9469863Z  ) 2025-01-24T00:45:43.9470252Z  parser.add_argument( 2025-01-24T00:45:43.9470937Z  "--github-actor", type=str, required=True, help="GitHub triggering_actor" 2025-01-24T00:45:43.9471637Z  ) 2025-01-24T00:45:43.9472253Z  parser.add_argument( 2025-01-24T00:45:43.9472951Z  "--github-issue-owner", type=str, required=True, help="GitHub issue owner" 2025-01-24T00:45:43.9473631Z  ) 2025-01-24T00:45:43.9474027Z  parser.add_argument( 2025-01-24T00:45:43.9474723Z  "--github-branch", type=str, required=True, help="Current GitHub branch or tag" 2025-01-24T00:45:43.9475420Z  ) 2025-01-24T00:45:43.9475853Z  parser.add_argument( 2025-01-24T00:45:43.9476337Z  "--github-ref-type", 2025-01-24T00:45:43.9476815Z  type=str, 2025-01-24T00:45:43.9477408Z  required=True, 2025-01-24T00:45:43.9477953Z  help="Current GitHub ref type, branch or tag", 2025-01-24T00:45:43.9478501Z  ) 2025-01-24T00:45:43.9478892Z  parser.add_argument( 2025-01-24T00:45:43.9479401Z  "--eligible-experiments", 2025-01-24T00:45:43.9479950Z  type=_str_comma_separated_to_set, 2025-01-24T00:45:43.9480512Z  required=False, 2025-01-24T00:45:43.9480979Z  default="", 2025-01-24T00:45:43.9482008Z  help="comma separated list of experiments to check, if omitted all experiments marked with default=True are checked", 2025-01-24T00:45:43.9483327Z  ) 2025-01-24T00:45:43.9484020Z  parser.add_argument( 2025-01-24T00:45:43.9484852Z  "--pr-number", 2025-01-24T00:45:43.9485578Z  type=str, 2025-01-24T00:45:43.9486035Z  required=False, 2025-01-24T00:45:43.9486507Z  default="", 2025-01-24T00:45:43.9487037Z  help="the optional PR number where this is run", 2025-01-24T00:45:43.9487637Z  ) 2025-01-24T00:45:43.9488049Z  2025-01-24T00:45:43.9488434Z  return parser.parse_args() 2025-01-24T00:45:43.9488925Z  2025-01-24T00:45:43.9489265Z  2025-01-24T00:45:43.9489706Z def get_gh_client(github_token: str) -> Github: 2025-01-24T00:45:43.9490301Z  auth = Auth.Token(github_token) 2025-01-24T00:45:43.9490813Z  return Github(auth=auth) 2025-01-24T00:45:43.9491287Z  2025-01-24T00:45:43.9491630Z  2025-01-24T00:45:43.9492367Z def get_issue(gh: Github, repo: str, issue_num: int) -> Issue: 2025-01-24T00:45:43.9493020Z  repo = gh.get_repo(repo) 2025-01-24T00:45:43.9493563Z  return repo.get_issue(number=issue_num) 2025-01-24T00:45:43.9494076Z  2025-01-24T00:45:43.9494422Z  2025-01-24T00:45:43.9494800Z def get_potential_pr_author( 2025-01-24T00:45:43.9495468Z  github_token: str, repo: str, username: str, ref_type: str, ref_name: str 2025-01-24T00:45:43.9496139Z ) -> str: 2025-01-24T00:45:43.9496689Z  # If the trigger was a new tag added by a bot, this is a ciflow case 2025-01-24T00:45:43.9497672Z  # Fetch the actual username from the original PR. The PR number is 2025-01-24T00:45:43.9498437Z  # embedded in the tag name: ciflow// 2025-01-24T00:45:43.9499009Z  2025-01-24T00:45:43.9499401Z  gh = get_gh_client(github_token) 2025-01-24T00:45:43.9499900Z  2025-01-24T00:45:43.9500384Z  if username == "pytorch-bot[bot]" and ref_type == "tag": 2025-01-24T00:45:43.9501028Z  split_tag = ref_name.split("/") 2025-01-24T00:45:43.9501536Z  if ( 2025-01-24T00:45:43.9502128Z  len(split_tag) == 3 2025-01-24T00:45:43.9502667Z  and split_tag[0] == "ciflow" 2025-01-24T00:45:43.9503203Z  and split_tag[2].isnumeric() 2025-01-24T00:45:43.9503706Z  ): 2025-01-24T00:45:43.9504134Z  pr_number = split_tag[2] 2025-01-24T00:45:43.9504630Z  try: 2025-01-24T00:45:43.9505116Z  repository = gh.get_repo(repo) 2025-01-24T00:45:43.9505762Z  pull = repository.get_pull(number=int(pr_number)) 2025-01-24T00:45:43.9506373Z  except Exception as e: 2025-01-24T00:45:43.9506923Z  raise Exception( # noqa: TRY002 2025-01-24T00:45:43.9507621Z  f"issue with pull request {pr_number} from repo {repository}" 2025-01-24T00:45:43.9508270Z  ) from e 2025-01-24T00:45:43.9508768Z  return pull.user.login 2025-01-24T00:45:43.9509385Z  # In all other cases, return the original input username 2025-01-24T00:45:43.9510106Z  return username 2025-01-24T00:45:43.9510536Z  2025-01-24T00:45:43.9510875Z  2025-01-24T00:45:43.9511301Z def is_exception_branch(branch: str) -> bool: 2025-01-24T00:45:43.9512040Z  """ 2025-01-24T00:45:43.9512744Z  Branches that get opted out of experiments by default, until they're explicitly enabled. 2025-01-24T00:45:43.9513884Z  """ 2025-01-24T00:45:43.9514774Z  return branch.split("/")[0] in {"main", "nightly", "release", "landchecks"} 2025-01-24T00:45:43.9515453Z  2025-01-24T00:45:43.9515783Z  2025-01-24T00:45:43.9516181Z def load_yaml(yaml_text: str) -> Any: 2025-01-24T00:45:43.9516685Z  try: 2025-01-24T00:45:43.9517166Z  data = yaml.safe_load(yaml_text) 2025-01-24T00:45:43.9517685Z  return data 2025-01-24T00:45:43.9518140Z  except yaml.YAMLError: 2025-01-24T00:45:43.9518671Z  log.exception("Error loading YAML") 2025-01-24T00:45:43.9519187Z  raise 2025-01-24T00:45:43.9519583Z  2025-01-24T00:45:43.9519913Z  2025-01-24T00:45:43.9520523Z def extract_settings_user_opt_in_from_text(rollout_state: str) -> Tuple[str, str]: 2025-01-24T00:45:43.9521260Z  """ 2025-01-24T00:45:43.9522075Z  Extracts the text with settings, if any, and the opted in users from the rollout state. 2025-01-24T00:45:43.9522808Z  2025-01-24T00:45:43.9523344Z  If the issue body contains "---" then the text above that is the settings 2025-01-24T00:45:43.9524098Z  and the text below is the list of opted in users. 2025-01-24T00:45:43.9524643Z  2025-01-24T00:45:43.9525204Z  If it doesn't contain "---" then the settings are empty and the rest is the users. 2025-01-24T00:45:43.9525891Z  """ 2025-01-24T00:45:43.9526362Z  rollout_state_parts = rollout_state.split("---") 2025-01-24T00:45:43.9526966Z  if len(rollout_state_parts) >= 2: 2025-01-24T00:45:43.9527599Z  return rollout_state_parts[0], rollout_state_parts[1] 2025-01-24T00:45:43.9528176Z  else: 2025-01-24T00:45:43.9528771Z  return "", rollout_state 2025-01-24T00:45:43.9529253Z  2025-01-24T00:45:43.9529580Z  2025-01-24T00:45:43.9529984Z class UserOptins(Dict[str, List[str]]): 2025-01-24T00:45:43.9530508Z  """ 2025-01-24T00:45:43.9531047Z  Dictionary of users with a list of features they have opted into 2025-01-24T00:45:43.9531677Z  """ 2025-01-24T00:45:43.9532227Z  2025-01-24T00:45:43.9532563Z  2025-01-24T00:45:43.9533101Z def parse_user_opt_in_from_text(user_optin_text: str) -> UserOptins: 2025-01-24T00:45:43.9533754Z  """ 2025-01-24T00:45:43.9534470Z  Parse the user opt-in text into a key value pair of username and the list of features they have opted into 2025-01-24T00:45:43.9535285Z  2025-01-24T00:45:43.9536072Z  Users are GitHub usernames with the @ prefix. Each user is also a comma-separated list of features/experiments to enable. 2025-01-24T00:45:43.9537042Z  - Example line: "@User1,lf,split_build" 2025-01-24T00:45:43.9537726Z  - A "#" prefix indicates the user is opted out of all experiments 2025-01-24T00:45:43.9538343Z  2025-01-24T00:45:43.9538672Z  2025-01-24T00:45:43.9539009Z  """ 2025-01-24T00:45:43.9539393Z  optins = UserOptins() 2025-01-24T00:45:43.9539904Z  for user in user_optin_text.split("\n"): 2025-01-24T00:45:43.9540467Z  user = user.strip("\r\n\t -") 2025-01-24T00:45:43.9541031Z  if not user or not user.startswith("@"): 2025-01-24T00:45:43.9541596Z  # Not a valid user. Skip 2025-01-24T00:45:43.9542397Z  continue 2025-01-24T00:45:43.9542820Z  2025-01-24T00:45:43.9543164Z  if user: 2025-01-24T00:45:43.9543646Z  usr_name = user.split(",")[0].strip("@") 2025-01-24T00:45:43.9544344Z  optins[usr_name] = [exp.strip(" ") for exp in user.split(",")[1:]] 2025-01-24T00:45:43.9544973Z  2025-01-24T00:45:43.9545327Z  return optins 2025-01-24T00:45:43.9545738Z  2025-01-24T00:45:43.9546074Z  2025-01-24T00:45:43.9546564Z def is_valid_experiment_name(experiment_name: str) -> bool: 2025-01-24T00:45:43.9547174Z  """ 2025-01-24T00:45:43.9547607Z  Check if the experiment name is valid. 2025-01-24T00:45:43.9548134Z  A valid name: 2025-01-24T00:45:43.9548800Z  - Contains only alphanumeric characters and the special characters "_" & "-" 2025-01-24T00:45:43.9549725Z  - The special characters "_" & "-" shouldn't be the first or last characters 2025-01-24T00:45:43.9550423Z  - Cannot contain spaces 2025-01-24T00:45:43.9550900Z  """ 2025-01-24T00:45:43.9551265Z  2025-01-24T00:45:43.9551726Z  valid_char_regex = r"^[a-zA-Z0-9]([\w-]*[a-zA-Z0-9])?$" 2025-01-24T00:45:43.9552670Z  valid = bool(re.match(valid_char_regex, experiment_name)) 2025-01-24T00:45:43.9553264Z  2025-01-24T00:45:43.9553607Z  if valid: 2025-01-24T00:45:43.9554020Z  return True 2025-01-24T00:45:43.9554443Z  2025-01-24T00:45:43.9554782Z  log.error( 2025-01-24T00:45:43.9556186Z  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." 2025-01-24T00:45:43.9557687Z  ) 2025-01-24T00:45:43.9558062Z  return False 2025-01-24T00:45:43.9558471Z  2025-01-24T00:45:43.9558806Z  2025-01-24T00:45:43.9559316Z def parse_settings_from_text(settings_text: str) -> Settings: 2025-01-24T00:45:43.9559946Z  """ 2025-01-24T00:45:43.9560680Z  Parse the experiments from the issue body into a list of ExperimentSettings 2025-01-24T00:45:43.9561381Z  """ 2025-01-24T00:45:43.9561744Z  try: 2025-01-24T00:45:43.9562369Z  if settings_text: 2025-01-24T00:45:43.9563112Z  # Escape the backtick as well so that we can have the settings in a code block on the GH issue 2025-01-24T00:45:43.9563883Z  # for easy reading 2025-01-24T00:45:43.9564694Z  # Note: Using ascii for the backtick so that the cat step in _runner-determinator.yml doesn't choke on 2025-01-24T00:45:43.9565597Z  # the backtick character in shell commands. 2025-01-24T00:45:43.9566217Z  backtick = chr(96) # backtick character 2025-01-24T00:45:43.9566886Z  settings_text = settings_text.strip(f"\r\n\t{backtick} ") 2025-01-24T00:45:43.9567552Z  settings = load_yaml(settings_text) 2025-01-24T00:45:43.9568053Z  2025-01-24T00:45:43.9568640Z  # For now we just load experiments. We can expand this if/when we add more settings 2025-01-24T00:45:43.9569367Z  experiments = {} 2025-01-24T00:45:43.9569823Z  2025-01-24T00:45:43.9570381Z  for exp_name, exp_settings in settings.get(SETTING_EXPERIMENTS).items(): 2025-01-24T00:45:43.9571148Z  if not is_valid_experiment_name(exp_name): 2025-01-24T00:45:43.9573211Z  # Exclude invalid experiments from the list. We log an error, but don't raise an exception so that other experiments can still be processed. 2025-01-24T00:45:43.9574521Z  continue 2025-01-24T00:45:43.9574982Z  2025-01-24T00:45:43.9575370Z  valid_settings = {} 2025-01-24T00:45:43.9575900Z  for setting in exp_settings: 2025-01-24T00:45:43.9576493Z  if setting not in Experiment._fields: 2025-01-24T00:45:43.9577064Z  log.warning( 2025-01-24T00:45:43.9577843Z  f"Unexpected setting in experiment: {setting} = {exp_settings[setting]}" 2025-01-24T00:45:43.9578540Z  ) 2025-01-24T00:45:43.9578997Z  else: 2025-01-24T00:45:43.9579544Z  valid_settings[setting] = exp_settings[setting] 2025-01-24T00:45:43.9580111Z  2025-01-24T00:45:43.9580591Z  experiments[exp_name] = Experiment(**valid_settings) 2025-01-24T00:45:43.9581229Z  return Settings(experiments) 2025-01-24T00:45:43.9581729Z  2025-01-24T00:45:43.9582427Z  except Exception: 2025-01-24T00:45:43.9582963Z  log.exception("Failed to parse settings") 2025-01-24T00:45:43.9583495Z  2025-01-24T00:45:43.9583852Z  return Settings() 2025-01-24T00:45:43.9584287Z  2025-01-24T00:45:43.9584626Z  2025-01-24T00:45:43.9585089Z def parse_settings(rollout_state: str) -> Settings: 2025-01-24T00:45:43.9585660Z  """ 2025-01-24T00:45:43.9586132Z  Parse settings, if any, from the rollout state. 2025-01-24T00:45:43.9586678Z  2025-01-24T00:45:43.9587210Z  If the issue body contains "---" then the text above that is the settings 2025-01-24T00:45:43.9587977Z  and the text below is the list of opted in users. 2025-01-24T00:45:43.9588530Z  2025-01-24T00:45:43.9589123Z  If it doesn't contain "---" then the settings are empty and the default values are used. 2025-01-24T00:45:43.9589833Z  """ 2025-01-24T00:45:43.9590414Z  settings_text, _ = extract_settings_user_opt_in_from_text(rollout_state) 2025-01-24T00:45:43.9591171Z  return parse_settings_from_text(settings_text) 2025-01-24T00:45:43.9591706Z  2025-01-24T00:45:43.9592315Z  2025-01-24T00:45:43.9592776Z def parse_users(rollout_state: str) -> UserOptins: 2025-01-24T00:45:43.9593340Z  """ 2025-01-24T00:45:43.9593757Z  Parse users from the rollout state. 2025-01-24T00:45:43.9594261Z  2025-01-24T00:45:43.9594596Z  """ 2025-01-24T00:45:43.9595146Z  _, users_text = extract_settings_user_opt_in_from_text(rollout_state) 2025-01-24T00:45:43.9595901Z  return parse_user_opt_in_from_text(users_text) 2025-01-24T00:45:43.9596434Z  2025-01-24T00:45:43.9596766Z  2025-01-24T00:45:43.9597376Z def is_user_opted_in(user: str, user_optins: UserOptins, experiment_name: str) -> bool: 2025-01-24T00:45:43.9598103Z  """ 2025-01-24T00:45:43.9598547Z  Check if a user is opted into an experiment 2025-01-24T00:45:43.9599097Z  """ 2025-01-24T00:45:43.9599582Z  return experiment_name in user_optins.get(user, []) 2025-01-24T00:45:43.9600153Z  2025-01-24T00:45:43.9600490Z  2025-01-24T00:45:43.9601100Z def is_user_opted_out(user: str, user_optins: UserOptins, experiment_name: str) -> bool: 2025-01-24T00:45:43.9601969Z  """ 2025-01-24T00:45:43.9602465Z  Check if a user explicitly opted out of an experiment 2025-01-24T00:45:43.9603040Z  """ 2025-01-24T00:45:43.9603575Z  # if the experiment is prefixed with a "-", then it's an opt-out 2025-01-24T00:45:43.9604266Z  experiment_optout = "-" + experiment_name 2025-01-24T00:45:43.9604916Z  if experiment_optout not in user_optins.get(user, []): 2025-01-24T00:45:43.9605648Z  return False 2025-01-24T00:45:43.9606077Z  2025-01-24T00:45:43.9606546Z  if is_user_opted_in(user, user_optins, experiment_name): 2025-01-24T00:45:43.9607149Z  log.warning( 2025-01-24T00:45:43.9607968Z  f"User {user} is opted into experiment {experiment_name}, but also opted out of it. Defaulting to opting out" 2025-01-24T00:45:43.9608822Z  ) 2025-01-24T00:45:43.9609197Z  2025-01-24T00:45:43.9609550Z  return True 2025-01-24T00:45:43.9609958Z  2025-01-24T00:45:43.9610290Z  2025-01-24T00:45:43.9610651Z def get_runner_prefix( 2025-01-24T00:45:43.9611114Z  rollout_state: str, 2025-01-24T00:45:43.9611617Z  workflow_requestors: Iterable[str], 2025-01-24T00:45:43.9612243Z  branch: str, 2025-01-24T00:45:43.9612775Z  eligible_experiments: FrozenSet[str] = frozenset(), 2025-01-24T00:45:43.9613387Z  is_canary: bool = False, 2025-01-24T00:45:43.9613861Z ) -> str: 2025-01-24T00:45:43.9614302Z  settings = parse_settings(rollout_state) 2025-01-24T00:45:43.9614900Z  user_optins = parse_users(rollout_state) 2025-01-24T00:45:43.9615425Z  2025-01-24T00:45:43.9615789Z  fleet_prefix = "" 2025-01-24T00:45:43.9616235Z  prefixes = [] 2025-01-24T00:45:43.9616899Z  for experiment_name, experiment_settings in settings.experiments.items(): 2025-01-24T00:45:43.9617845Z  if not experiment_settings.all_branches and is_exception_branch(branch): 2025-01-24T00:45:43.9618539Z  log.info( 2025-01-24T00:45:43.9619242Z  f"Branch {branch} is an exception branch. Not enabling experiment {experiment_name}." 2025-01-24T00:45:43.9619971Z  ) 2025-01-24T00:45:43.9620392Z  continue 2025-01-24T00:45:43.9620825Z  2025-01-24T00:45:43.9621201Z  if eligible_experiments: 2025-01-24T00:45:43.9621782Z  if experiment_name not in eligible_experiments: 2025-01-24T00:45:43.9622665Z  exp_list = ", ".join(eligible_experiments) 2025-01-24T00:45:43.9623346Z  log.info( 2025-01-24T00:45:43.9624145Z  f"Skipping experiment '{experiment_name}', as it is not in the eligible_experiments list: {exp_list}" 2025-01-24T00:45:43.9624951Z  ) 2025-01-24T00:45:43.9625376Z  continue 2025-01-24T00:45:43.9625886Z  elif not experiment_settings.default: 2025-01-24T00:45:43.9626418Z  log.info( 2025-01-24T00:45:43.9627098Z  f"Skipping experiment '{experiment_name}', as it is not a default experiment" 2025-01-24T00:45:43.9627808Z  ) 2025-01-24T00:45:43.9628211Z  continue 2025-01-24T00:45:43.9628632Z  2025-01-24T00:45:43.9629103Z  # Is any workflow_requestor opted out to this experiment? 2025-01-24T00:45:43.9629703Z  opted_out_users = [ 2025-01-24T00:45:43.9630179Z  requestor 2025-01-24T00:45:43.9630680Z  for requestor in workflow_requestors 2025-01-24T00:45:43.9631353Z  if is_user_opted_out(requestor, user_optins, experiment_name) 2025-01-24T00:45:43.9632166Z  ] 2025-01-24T00:45:43.9632565Z  2025-01-24T00:45:43.9633214Z  if opted_out_users: 2025-01-24T00:45:43.9634052Z  log.info( 2025-01-24T00:45:43.9635177Z  f"{', '.join(opted_out_users)} have opted out of experiment {experiment_name}." 2025-01-24T00:45:43.9636371Z  ) 2025-01-24T00:45:43.9636856Z  continue 2025-01-24T00:45:43.9637496Z  2025-01-24T00:45:43.9637972Z  # Is any workflow_requestor opted in to this experiment? 2025-01-24T00:45:43.9638585Z  opted_in_users = [ 2025-01-24T00:45:43.9639055Z  requestor 2025-01-24T00:45:43.9639553Z  for requestor in workflow_requestors 2025-01-24T00:45:43.9640230Z  if is_user_opted_in(requestor, user_optins, experiment_name) 2025-01-24T00:45:43.9640834Z  ] 2025-01-24T00:45:43.9641205Z  2025-01-24T00:45:43.9641562Z  enabled = False 2025-01-24T00:45:43.9642214Z  if opted_in_users: 2025-01-24T00:45:43.9642685Z  log.info( 2025-01-24T00:45:43.9643321Z  f"{', '.join(opted_in_users)} have opted into experiment {experiment_name}." 2025-01-24T00:45:43.9643990Z  ) 2025-01-24T00:45:43.9644394Z  enabled = True 2025-01-24T00:45:43.9644852Z  2025-01-24T00:45:43.9645272Z  elif experiment_settings.rollout_perc: 2025-01-24T00:45:43.9646119Z  # If no user is opted in, then we randomly enable the experiment based on the rollout percentage 2025-01-24T00:45:43.9647042Z  if random.uniform(0, 100) <= experiment_settings.rollout_perc: 2025-01-24T00:45:43.9647678Z  log.info( 2025-01-24T00:45:43.9648550Z  f"Based on rollout percentage of {experiment_settings.rollout_perc}%, enabling experiment {experiment_name}." 2025-01-24T00:45:43.9649433Z  ) 2025-01-24T00:45:43.9649870Z  enabled = True 2025-01-24T00:45:43.9650340Z  2025-01-24T00:45:43.9650687Z  if enabled: 2025-01-24T00:45:43.9651152Z  label = experiment_name 2025-01-24T00:45:43.9651725Z  if experiment_name == LF_FLEET_EXPERIMENT: 2025-01-24T00:45:43.9652650Z  # We give some special treatment to the "lf" experiment since determines the fleet we use 2025-01-24T00:45:43.9653499Z  # - If it's enabled, then we always list it's prefix first 2025-01-24T00:45:43.9654376Z  # - If we're in the canary branch, then we append ".c" to the lf prefix 2025-01-24T00:45:43.9655028Z  if is_canary: 2025-01-24T00:45:43.9655543Z  label += CANARY_FLEET_SUFFIX 2025-01-24T00:45:43.9656085Z  fleet_prefix = label 2025-01-24T00:45:43.9656578Z  else: 2025-01-24T00:45:43.9657041Z  prefixes.append(label) 2025-01-24T00:45:43.9657543Z  2025-01-24T00:45:43.9657903Z  if len(prefixes) > 1: 2025-01-24T00:45:43.9658361Z  log.error( 2025-01-24T00:45:43.9659375Z  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:])}" 2025-01-24T00:45:43.9660429Z  ) 2025-01-24T00:45:43.9660839Z  prefixes = prefixes[:1] 2025-01-24T00:45:43.9661319Z  2025-01-24T00:45:43.9661687Z  # Fleet always comes first 2025-01-24T00:45:43.9662282Z  if fleet_prefix: 2025-01-24T00:45:43.9662763Z  prefixes.insert(0, fleet_prefix) 2025-01-24T00:45:43.9663270Z  2025-01-24T00:45:43.9663713Z  return ".".join(prefixes) + "." if prefixes else "" 2025-01-24T00:45:43.9664277Z  2025-01-24T00:45:43.9664614Z  2025-01-24T00:45:43.9665238Z def get_rollout_state_from_issue(github_token: str, repo: str, issue_num: int) -> str: 2025-01-24T00:45:43.9666021Z  """ 2025-01-24T00:45:43.9666625Z  Gets the first comment of the issue, which contains the desired rollout state. 2025-01-24T00:45:43.9667438Z  2025-01-24T00:45:43.9668017Z  The default issue we use - https://github.com/pytorch/test-infra/issues/5132 2025-01-24T00:45:43.9668715Z  """ 2025-01-24T00:45:43.9669120Z  gh = get_gh_client(github_token) 2025-01-24T00:45:43.9669678Z  issue = get_issue(gh, repo, issue_num) 2025-01-24T00:45:43.9670333Z  return str(issue.get_comments()[0].body.strip("\n\t ")) 2025-01-24T00:45:43.9670954Z  2025-01-24T00:45:43.9671301Z  2025-01-24T00:45:43.9672136Z def download_json(url: str, headers: Dict[str, str], num_retries: int = 3) -> Any: 2025-01-24T00:45:43.9672895Z  for _ in range(num_retries): 2025-01-24T00:45:43.9673386Z  try: 2025-01-24T00:45:43.9673841Z  req = Request(url=url, headers=headers) 2025-01-24T00:45:43.9674507Z  content = urlopen(req, timeout=5).read().decode("utf-8") 2025-01-24T00:45:43.9675147Z  return json.loads(content) 2025-01-24T00:45:43.9675688Z  except Exception as e: 2025-01-24T00:45:43.9676260Z  log.warning(f"Could not download {url}: {e}") 2025-01-24T00:45:43.9676798Z  2025-01-24T00:45:43.9677367Z  log.warning(f"All {num_retries} retries exhausted, downloading {url} failed") 2025-01-24T00:45:43.9678071Z  return {} 2025-01-24T00:45:43.9678458Z  2025-01-24T00:45:43.9678796Z  2025-01-24T00:45:43.9679226Z @lru_cache(maxsize=None) 2025-01-24T00:45:43.9679951Z def get_pr_info(github_repo: str, github_token: str, pr_number: int) -> Dict[str, Any]: 2025-01-24T00:45:43.9680672Z  """ 2025-01-24T00:45:43.9681081Z  Dynamically get PR information 2025-01-24T00:45:43.9681570Z  """ 2025-01-24T00:45:43.9682240Z  github_api = f"https://api.github.com/repos/{github_repo}" 2025-01-24T00:45:43.9683217Z  headers = { 2025-01-24T00:45:43.9684193Z  "Accept": "application/vnd.github.v3+json", 2025-01-24T00:45:43.9685252Z  "Authorization": f"token {github_token}", 2025-01-24T00:45:43.9685929Z  } 2025-01-24T00:45:43.9686389Z  json_response: Dict[str, Any] = download_json( 2025-01-24T00:45:43.9687181Z  url=f"{github_api}/issues/{pr_number}", 2025-01-24T00:45:43.9687747Z  headers=headers, 2025-01-24T00:45:43.9688188Z  ) 2025-01-24T00:45:43.9688546Z  2025-01-24T00:45:43.9688907Z  if not json_response: 2025-01-24T00:45:43.9689510Z  log.warning(f"Failed to get the labels for #{pr_number}") 2025-01-24T00:45:43.9690124Z  return {} 2025-01-24T00:45:43.9690541Z  2025-01-24T00:45:43.9690897Z  return json_response 2025-01-24T00:45:43.9691392Z  2025-01-24T00:45:43.9691738Z  2025-01-24T00:45:43.9692462Z def get_labels(github_repo: str, github_token: str, pr_number: int) -> Set[str]: 2025-01-24T00:45:43.9693176Z  """ 2025-01-24T00:45:43.9693726Z  Dynamically get the latest list of labels from the pull request 2025-01-24T00:45:43.9694351Z  """ 2025-01-24T00:45:43.9694862Z  pr_info = get_pr_info(github_repo, github_token, pr_number) 2025-01-24T00:45:43.9695464Z  return { 2025-01-24T00:45:43.9696063Z  label.get("name") for label in pr_info.get("labels", []) if label.get("name") 2025-01-24T00:45:43.9696736Z  } 2025-01-24T00:45:43.9697098Z  2025-01-24T00:45:43.9697433Z  2025-01-24T00:45:43.9697788Z def main() -> None: 2025-01-24T00:45:43.9698243Z  args = parse_args() 2025-01-24T00:45:43.9698683Z  2025-01-24T00:45:43.9699109Z  runner_label_prefix = DEFAULT_LABEL_PREFIX 2025-01-24T00:45:43.9699818Z  2025-01-24T00:45:43.9700429Z  # Check if the PR is opt-out 2025-01-24T00:45:43.9701554Z  if args.pr_number: 2025-01-24T00:45:43.9702883Z  labels = get_labels(args.github_repo, args.github_token, int(args.pr_number)) 2025-01-24T00:45:43.9704089Z  if OPT_OUT_LABEL in labels: 2025-01-24T00:45:43.9704911Z  log.info( 2025-01-24T00:45:43.9706146Z  f"Opt-out runner determinator because #{args.pr_number} has {OPT_OUT_LABEL} label" 2025-01-24T00:45:43.9707471Z  ) 2025-01-24T00:45:43.9708509Z  set_github_output(GH_OUTPUT_KEY_LABEL_TYPE, runner_label_prefix) 2025-01-24T00:45:43.9709641Z  sys.exit() 2025-01-24T00:45:43.9710436Z  2025-01-24T00:45:43.9711044Z  try: 2025-01-24T00:45:43.9712007Z  rollout_state = get_rollout_state_from_issue( 2025-01-24T00:45:43.9712973Z  args.github_token, args.github_issue_repo, args.github_issue 2025-01-24T00:45:43.9713624Z  ) 2025-01-24T00:45:43.9714094Z  2025-01-24T00:45:43.9714756Z  username = get_potential_pr_author( 2025-01-24T00:45:43.9715319Z  args.github_token, 2025-01-24T00:45:43.9715819Z  args.github_repo, 2025-01-24T00:45:43.9716336Z  args.github_actor, 2025-01-24T00:45:43.9716852Z  args.github_ref_type, 2025-01-24T00:45:43.9717363Z  args.github_branch, 2025-01-24T00:45:43.9717839Z  ) 2025-01-24T00:45:43.9718206Z  2025-01-24T00:45:43.9718697Z  is_canary = args.github_repo == "pytorch/pytorch-canary" 2025-01-24T00:45:43.9719296Z  2025-01-24T00:45:43.9719708Z  runner_label_prefix = get_runner_prefix( 2025-01-24T00:45:43.9720260Z  rollout_state, 2025-01-24T00:45:43.9720790Z  (args.github_issue_owner, username), 2025-01-24T00:45:43.9721372Z  args.github_branch, 2025-01-24T00:45:43.9722112Z  args.eligible_experiments, 2025-01-24T00:45:43.9722649Z  is_canary, 2025-01-24T00:45:43.9723088Z  ) 2025-01-24T00:45:43.9723511Z  2025-01-24T00:45:43.9723880Z  except Exception as e: 2025-01-24T00:45:43.9724523Z  log.error( 2025-01-24T00:45:43.9725231Z  f"Failed to get issue. Defaulting to Meta runners and no experiments. Exception: {e}" 2025-01-24T00:45:43.9725965Z  ) 2025-01-24T00:45:43.9726333Z  2025-01-24T00:45:43.9726867Z  set_github_output(GH_OUTPUT_KEY_LABEL_TYPE, runner_label_prefix) 2025-01-24T00:45:43.9727501Z  2025-01-24T00:45:43.9727834Z  2025-01-24T00:45:43.9728193Z if __name__ == "__main__": 2025-01-24T00:45:43.9728651Z  main() 2025-01-24T00:45:43.9729020Z  2025-01-24T00:45:43.9729368Z EOF 2025-01-24T00:45:43.9729722Z  2025-01-24T00:45:43.9730091Z cat runner_determinator.py 2025-01-24T00:45:44.0113457Z shell: /usr/bin/bash -e {0} 2025-01-24T00:45:44.0114273Z env: 2025-01-24T00:45:44.0114961Z GITHUB_TOKEN: *** 2025-01-24T00:45:44.0115401Z ISSUE_NUMBER: 5132 2025-01-24T00:45:44.0115897Z TRIGGERING_ACTOR: pytorch-bot[bot] 2025-01-24T00:45:44.0116437Z ISSUE_OWNER: 2025-01-24T00:45:44.0116859Z CHECK_EXPERIMENTS: 2025-01-24T00:45:44.0117301Z PR_NUMBER: 2025-01-24T00:45:44.0117677Z ##[endgroup] 2025-01-24T00:45:44.0416839Z # flake8: noqa: G004 2025-01-24T00:45:44.0417346Z 2025-01-24T00:45:44.0418061Z # Note: Copies of this script in runner_determinator.py and _runner-determinator.yml 2025-01-24T00:45:44.0419633Z # must be kept in sync. You can do it easily by running the following command: 2025-01-24T00:45:44.0420970Z # python .github/scripts/update_runner_determinator.py 2025-01-24T00:45:44.0421708Z 2025-01-24T00:45:44.0422476Z """ 2025-01-24T00:45:44.0423504Z This runner determinator is used to determine which set of runners to run a 2025-01-24T00:45:44.0425086Z GitHub job on. It uses the first comment of a GitHub issue (by default 2025-01-24T00:45:44.0426663Z https://github.com/pytorch/test-infra/issues/5132) to define the configuration 2025-01-24T00:45:44.0428078Z of which runners should be used to run which job. 2025-01-24T00:45:44.0428766Z 2025-01-24T00:45:44.0429422Z The configuration has two parts, the settings and a list of opted-in users, 2025-01-24T00:45:44.0431017Z separated by a line containing "---". If the line is not present, the 2025-01-24T00:45:44.0432845Z settings are considered to be empty with only the second part, the user 2025-01-24T00:45:44.0434060Z list, defined. 2025-01-24T00:45:44.0434575Z 2025-01-24T00:45:44.0435229Z The first part is a YAML block that defines the rollout settings. This can be 2025-01-24T00:45:44.0436831Z used to define any settings that are needed to determine which runners to use. 2025-01-24T00:45:44.0438299Z It's fields are defined by the RolloutSettings class below. 2025-01-24T00:45:44.0439056Z 2025-01-24T00:45:44.0439693Z The second part is a list of users who are explicitly opted in to the LF fleet. 2025-01-24T00:45:44.0441221Z The user list is also a comma separated list of additional features or 2025-01-24T00:45:44.0442764Z experiments which the user could be opted in to. 2025-01-24T00:45:44.0443485Z 2025-01-24T00:45:44.0443839Z The user list has the following rules: 2025-01-24T00:45:44.0444439Z 2025-01-24T00:45:44.0444974Z - Users are GitHub usernames, which must start with the @ prefix 2025-01-24T00:45:44.0446636Z - Each user is also a comma-separated list of features/experiments to enable 2025-01-24T00:45:44.0448012Z - A "#" prefix opts the user out of all experiments 2025-01-24T00:45:44.0448720Z 2025-01-24T00:45:44.0449036Z Example config: 2025-01-24T00:45:44.0449812Z # A list of experiments that can be opted into. 2025-01-24T00:45:44.0450950Z # This defines the behavior they'll induce when opted into. 2025-01-24T00:45:44.0452282Z # Expected syntax is: 2025-01-24T00:45:44.0453415Z # [experiment_name]: # Name of the experiment. Also used for the label prefix. 2025-01-24T00:45:44.0455147Z # rollout_perc: [int] # % of workflows to run with this experiment when users are not opted in. 2025-01-24T00:45:44.0456508Z 2025-01-24T00:45:44.0456850Z experiments: 2025-01-24T00:45:44.0457506Z lf: 2025-01-24T00:45:44.0458135Z rollout_percent: 25 2025-01-24T00:45:44.0458897Z all_branches: false 2025-01-24T00:45:44.0459628Z default: true 2025-01-24T00:45:44.0460302Z --- 2025-01-24T00:45:44.0460638Z 2025-01-24T00:45:44.0460926Z # Opt-ins: 2025-01-24T00:45:44.0462183Z # Users can opt into the LF fleet by adding their GitHub username to this list 2025-01-24T00:45:44.0463748Z # and specifying experiments to enable in a comma-separated list. 2025-01-24T00:45:44.0465136Z # To always opt out of an experiment, prefix it with a "-". 2025-01-24T00:45:44.0466305Z # Experiments should be from the above list. 2025-01-24T00:45:44.0466968Z 2025-01-24T00:45:44.0467256Z @User1,-lf,split_build 2025-01-24T00:45:44.0467990Z @User2,lf 2025-01-24T00:45:44.0468616Z @User3,split_build 2025-01-24T00:45:44.0469286Z """ 2025-01-24T00:45:44.0469604Z 2025-01-24T00:45:44.0469889Z import json 2025-01-24T00:45:44.0470505Z import logging 2025-01-24T00:45:44.0471150Z import os 2025-01-24T00:45:44.0472016Z import random 2025-01-24T00:45:44.0472725Z import re 2025-01-24T00:45:44.0473361Z import sys 2025-01-24T00:45:44.0474037Z from argparse import ArgumentParser 2025-01-24T00:45:44.0474939Z from functools import lru_cache 2025-01-24T00:45:44.0475747Z from logging import LogRecord 2025-01-24T00:45:44.0476910Z from typing import Any, Dict, FrozenSet, Iterable, List, NamedTuple, Set, Tuple 2025-01-24T00:45:44.0478293Z from urllib.request import Request, urlopen 2025-01-24T00:45:44.0479033Z 2025-01-24T00:45:44.0479333Z import yaml 2025-01-24T00:45:44.0480337Z from github import Auth, Github 2025-01-24T00:45:44.0481222Z from github.Issue import Issue 2025-01-24T00:45:44.0481754Z 2025-01-24T00:45:44.0481779Z 2025-01-24T00:45:44.0482405Z DEFAULT_LABEL_PREFIX = "" # use meta runners 2025-01-24T00:45:44.0483592Z WORKFLOW_LABEL_LF = "lf." # use runners from the linux foundation 2025-01-24T00:45:44.0485123Z WORKFLOW_LABEL_LF_CANARY = "lf.c." # use canary runners from the linux foundation 2025-01-24T00:45:44.0486154Z 2025-01-24T00:45:44.0486557Z GITHUB_OUTPUT = os.getenv("GITHUB_OUTPUT", "") 2025-01-24T00:45:44.0487563Z GH_OUTPUT_KEY_AMI = "runner-ami" 2025-01-24T00:45:44.0488431Z GH_OUTPUT_KEY_LABEL_TYPE = "label-type" 2025-01-24T00:45:44.0489388Z OPT_OUT_LABEL = "no-runner-experiments" 2025-01-24T00:45:44.0490012Z 2025-01-24T00:45:44.0490350Z SETTING_EXPERIMENTS = "experiments" 2025-01-24T00:45:44.0490926Z 2025-01-24T00:45:44.0491224Z LF_FLEET_EXPERIMENT = "lf" 2025-01-24T00:45:44.0492170Z CANARY_FLEET_SUFFIX = ".c" 2025-01-24T00:45:44.0492688Z 2025-01-24T00:45:44.0492699Z 2025-01-24T00:45:44.0493027Z class Experiment(NamedTuple): 2025-01-24T00:45:44.0493795Z rollout_perc: float = ( 2025-01-24T00:45:44.0494847Z 0 # Percentage of workflows to experiment on when user is not opted-in. 2025-01-24T00:45:44.0496000Z ) 2025-01-24T00:45:44.0496624Z all_branches: bool = ( 2025-01-24T00:45:44.0497694Z False # If True, the experiment is also enabled on the exception branches 2025-01-24T00:45:44.0498891Z ) 2025-01-24T00:45:44.0499494Z default: bool = ( 2025-01-24T00:45:44.0500479Z True # If True, the experiment is enabled by default for all queries 2025-01-24T00:45:44.0501654Z ) 2025-01-24T00:45:44.0502210Z 2025-01-24T00:45:44.0502531Z # Add more fields as needed 2025-01-24T00:45:44.0503079Z 2025-01-24T00:45:44.0503090Z 2025-01-24T00:45:44.0503402Z class Settings(NamedTuple): 2025-01-24T00:45:44.0504194Z """ 2025-01-24T00:45:44.0504994Z Settings for the experiments that can be opted into. 2025-01-24T00:45:44.0506039Z """ 2025-01-24T00:45:44.0506381Z 2025-01-24T00:45:44.0506731Z experiments: Dict[str, Experiment] = {} 2025-01-24T00:45:44.0507353Z 2025-01-24T00:45:44.0507362Z 2025-01-24T00:45:44.0507706Z class ColorFormatter(logging.Formatter): 2025-01-24T00:45:44.0508740Z """Color codes the log messages based on the log level""" 2025-01-24T00:45:44.0509775Z 2025-01-24T00:45:44.0510070Z COLORS = { 2025-01-24T00:45:44.0510737Z "WARNING": "\033[33m", # Yellow 2025-01-24T00:45:44.0511632Z "ERROR": "\033[31m", # Red 2025-01-24T00:45:44.0512770Z "CRITICAL": "\033[31m", # Red 2025-01-24T00:45:44.0513627Z "INFO": "\033[0m", # Reset 2025-01-24T00:45:44.0514475Z "DEBUG": "\033[0m", # Reset 2025-01-24T00:45:44.0515293Z } 2025-01-24T00:45:44.0515637Z 2025-01-24T00:45:44.0516013Z def format(self, record: LogRecord) -> str: 2025-01-24T00:45:44.0517285Z log_color = self.COLORS.get(record.levelname, "\033[0m") # Default to reset 2025-01-24T00:45:44.0518660Z record.msg = f"{log_color}{record.msg}\033[0m" 2025-01-24T00:45:44.0519663Z return super().format(record) 2025-01-24T00:45:44.0520264Z 2025-01-24T00:45:44.0520274Z 2025-01-24T00:45:44.0520600Z handler = logging.StreamHandler() 2025-01-24T00:45:44.0522063Z handler.setFormatter(ColorFormatter(fmt="%(levelname)-8s: %(message)s")) 2025-01-24T00:45:44.0523053Z 2025-01-24T00:45:44.0523475Z log = logging.getLogger(os.path.basename(__file__)) 2025-01-24T00:45:44.0524445Z log.addHandler(handler) 2025-01-24T00:45:44.0525171Z log.setLevel(logging.INFO) 2025-01-24T00:45:44.0525636Z 2025-01-24T00:45:44.0525646Z 2025-01-24T00:45:44.0526047Z def set_github_output(key: str, value: str) -> None: 2025-01-24T00:45:44.0526989Z """ 2025-01-24T00:45:44.0527830Z Defines outputs of the github action that invokes this script 2025-01-24T00:45:44.0528890Z """ 2025-01-24T00:45:44.0529481Z if not GITHUB_OUTPUT: 2025-01-24T00:45:44.0531303Z # See https://github.blog/changelog/2022-10-11-github-actions-deprecating-save-state-and-set-output-commands/ for deprecation notice 2025-01-24T00:45:44.0533697Z log.warning( 2025-01-24T00:45:44.0535126Z "No env var found for GITHUB_OUTPUT, you must be running this code locally. Falling back to the deprecated print method." 2025-01-24T00:45:44.0536733Z ) 2025-01-24T00:45:44.0551010Z print(f"::set-output name={key}::{value}") 2025-01-24T00:45:44.0552179Z return 2025-01-24T00:45:44.0552511Z 2025-01-24T00:45:44.0552710Z with open(GITHUB_OUTPUT, "a") as f: 2025-01-24T00:45:44.0553274Z log.info(f"Setting output: {key}='{value}'") 2025-01-24T00:45:44.0553813Z f.write(f"{key}={value}\n") 2025-01-24T00:45:44.0554124Z 2025-01-24T00:45:44.0554131Z 2025-01-24T00:45:44.0554415Z def _str_comma_separated_to_set(value: str) -> FrozenSet[str]: 2025-01-24T00:45:44.0555024Z return frozenset( 2025-01-24T00:45:44.0555600Z filter(lambda itm: itm != "", map(str.strip, value.strip(" \n\t").split(","))) 2025-01-24T00:45:44.0556256Z ) 2025-01-24T00:45:44.0556443Z 2025-01-24T00:45:44.0556455Z 2025-01-24T00:45:44.0556628Z def parse_args() -> Any: 2025-01-24T00:45:44.0557160Z parser = ArgumentParser("Get dynamic rollout settings") 2025-01-24T00:45:44.0557995Z parser.add_argument("--github-token", type=str, required=True, help="GitHub token") 2025-01-24T00:45:44.0558726Z parser.add_argument( 2025-01-24T00:45:44.0559157Z "--github-issue-repo", 2025-01-24T00:45:44.0559588Z type=str, 2025-01-24T00:45:44.0559960Z required=False, 2025-01-24T00:45:44.0560381Z default="pytorch/test-infra", 2025-01-24T00:45:44.0560882Z help="GitHub repo to get the issue", 2025-01-24T00:45:44.0561357Z ) 2025-01-24T00:45:44.0561691Z parser.add_argument( 2025-01-24T00:45:44.0562323Z "--github-repo", 2025-01-24T00:45:44.0562724Z type=str, 2025-01-24T00:45:44.0563090Z required=True, 2025-01-24T00:45:44.0563520Z help="GitHub repo where CI is running", 2025-01-24T00:45:44.0564020Z ) 2025-01-24T00:45:44.0564351Z parser.add_argument( 2025-01-24T00:45:44.0564916Z "--github-issue", type=int, required=True, help="GitHub issue number" 2025-01-24T00:45:44.0565537Z ) 2025-01-24T00:45:44.0565870Z parser.add_argument( 2025-01-24T00:45:44.0566653Z "--github-actor", type=str, required=True, help="GitHub triggering_actor" 2025-01-24T00:45:44.0567310Z ) 2025-01-24T00:45:44.0567670Z parser.add_argument( 2025-01-24T00:45:44.0568283Z "--github-issue-owner", type=str, required=True, help="GitHub issue owner" 2025-01-24T00:45:44.0568932Z ) 2025-01-24T00:45:44.0569273Z parser.add_argument( 2025-01-24T00:45:44.0569889Z "--github-branch", type=str, required=True, help="Current GitHub branch or tag" 2025-01-24T00:45:44.0570549Z ) 2025-01-24T00:45:44.0570885Z parser.add_argument( 2025-01-24T00:45:44.0571307Z "--github-ref-type", 2025-01-24T00:45:44.0571729Z type=str, 2025-01-24T00:45:44.0572295Z required=True, 2025-01-24T00:45:44.0572749Z help="Current GitHub ref type, branch or tag", 2025-01-24T00:45:44.0573257Z ) 2025-01-24T00:45:44.0573592Z parser.add_argument( 2025-01-24T00:45:44.0574018Z "--eligible-experiments", 2025-01-24T00:45:44.0574496Z type=_str_comma_separated_to_set, 2025-01-24T00:45:44.0574981Z required=False, 2025-01-24T00:45:44.0575371Z default="", 2025-01-24T00:45:44.0576148Z help="comma separated list of experiments to check, if omitted all experiments marked with default=True are checked", 2025-01-24T00:45:44.0577004Z ) 2025-01-24T00:45:44.0577347Z parser.add_argument( 2025-01-24T00:45:44.0577751Z "--pr-number", 2025-01-24T00:45:44.0578141Z type=str, 2025-01-24T00:45:44.0578512Z required=False, 2025-01-24T00:45:44.0578890Z default="", 2025-01-24T00:45:44.0579323Z help="the optional PR number where this is run", 2025-01-24T00:45:44.0579983Z ) 2025-01-24T00:45:44.0580160Z 2025-01-24T00:45:44.0580337Z return parser.parse_args() 2025-01-24T00:45:44.0580628Z 2025-01-24T00:45:44.0580635Z 2025-01-24T00:45:44.0580850Z def get_gh_client(github_token: str) -> Github: 2025-01-24T00:45:44.0581387Z auth = Auth.Token(github_token) 2025-01-24T00:45:44.0582070Z return Github(auth=auth) 2025-01-24T00:45:44.0582425Z 2025-01-24T00:45:44.0582434Z 2025-01-24T00:45:44.0582719Z def get_issue(gh: Github, repo: str, issue_num: int) -> Issue: 2025-01-24T00:45:44.0583308Z repo = gh.get_repo(repo) 2025-01-24T00:45:44.0583782Z return repo.get_issue(number=issue_num) 2025-01-24T00:45:44.0584119Z 2025-01-24T00:45:44.0584125Z 2025-01-24T00:45:44.0584305Z def get_potential_pr_author( 2025-01-24T00:45:44.0584899Z github_token: str, repo: str, username: str, ref_type: str, ref_name: str 2025-01-24T00:45:44.0585530Z ) -> str: 2025-01-24T00:45:44.0586018Z # If the trigger was a new tag added by a bot, this is a ciflow case 2025-01-24T00:45:44.0586766Z # Fetch the actual username from the original PR. The PR number is 2025-01-24T00:45:44.0587455Z # embedded in the tag name: ciflow// 2025-01-24T00:45:44.0587845Z 2025-01-24T00:45:44.0588030Z gh = get_gh_client(github_token) 2025-01-24T00:45:44.0588338Z 2025-01-24T00:45:44.0588597Z if username == "pytorch-bot[bot]" and ref_type == "tag": 2025-01-24T00:45:44.0589190Z split_tag = ref_name.split("/") 2025-01-24T00:45:44.0589661Z if ( 2025-01-24T00:45:44.0590009Z len(split_tag) == 3 2025-01-24T00:45:44.0590457Z and split_tag[0] == "ciflow" 2025-01-24T00:45:44.0590943Z and split_tag[2].isnumeric() 2025-01-24T00:45:44.0591394Z ): 2025-01-24T00:45:44.0591752Z pr_number = split_tag[2] 2025-01-24T00:45:44.0592401Z try: 2025-01-24T00:45:44.0592794Z repository = gh.get_repo(repo) 2025-01-24T00:45:44.0593376Z pull = repository.get_pull(number=int(pr_number)) 2025-01-24T00:45:44.0593948Z except Exception as e: 2025-01-24T00:45:44.0594424Z raise Exception( # noqa: TRY002 2025-01-24T00:45:44.0595052Z f"issue with pull request {pr_number} from repo {repository}" 2025-01-24T00:45:44.0595679Z ) from e 2025-01-24T00:45:44.0596236Z return pull.user.login 2025-01-24T00:45:44.0596791Z # In all other cases, return the original input username 2025-01-24T00:45:44.0597337Z return username 2025-01-24T00:45:44.0597558Z 2025-01-24T00:45:44.0597566Z 2025-01-24T00:45:44.0597775Z def is_exception_branch(branch: str) -> bool: 2025-01-24T00:45:44.0598270Z """ 2025-01-24T00:45:44.0598858Z Branches that get opted out of experiments by default, until they're explicitly enabled. 2025-01-24T00:45:44.0599562Z """ 2025-01-24T00:45:44.0600080Z return branch.split("/")[0] in {"main", "nightly", "release", "landchecks"} 2025-01-24T00:45:44.0600566Z 2025-01-24T00:45:44.0600572Z 2025-01-24T00:45:44.0600766Z def load_yaml(yaml_text: str) -> Any: 2025-01-24T00:45:44.0601217Z try: 2025-01-24T00:45:44.0601576Z data = yaml.safe_load(yaml_text) 2025-01-24T00:45:44.0602232Z return data 2025-01-24T00:45:44.0602622Z except yaml.YAMLError: 2025-01-24T00:45:44.0603076Z log.exception("Error loading YAML") 2025-01-24T00:45:44.0603574Z raise 2025-01-24T00:45:44.0603769Z 2025-01-24T00:45:44.0603776Z 2025-01-24T00:45:44.0604159Z def extract_settings_user_opt_in_from_text(rollout_state: str) -> Tuple[str, str]: 2025-01-24T00:45:44.0604853Z """ 2025-01-24T00:45:44.0605423Z Extracts the text with settings, if any, and the opted in users from the rollout state. 2025-01-24T00:45:44.0605981Z 2025-01-24T00:45:44.0606307Z If the issue body contains "---" then the text above that is the settings 2025-01-24T00:45:44.0607003Z and the text below is the list of opted in users. 2025-01-24T00:45:44.0607381Z 2025-01-24T00:45:44.0607723Z If it doesn't contain "---" then the settings are empty and the rest is the users. 2025-01-24T00:45:44.0608508Z """ 2025-01-24T00:45:44.0608911Z rollout_state_parts = rollout_state.split("---") 2025-01-24T00:45:44.0609464Z if len(rollout_state_parts) >= 2: 2025-01-24T00:45:44.0610022Z return rollout_state_parts[0], rollout_state_parts[1] 2025-01-24T00:45:44.0610580Z else: 2025-01-24T00:45:44.0610940Z return "", rollout_state 2025-01-24T00:45:44.0611224Z 2025-01-24T00:45:44.0611231Z 2025-01-24T00:45:44.0611423Z class UserOptins(Dict[str, List[str]]): 2025-01-24T00:45:44.0612047Z """ 2025-01-24T00:45:44.0612544Z Dictionary of users with a list of features they have opted into 2025-01-24T00:45:44.0613149Z """ 2025-01-24T00:45:44.0613332Z 2025-01-24T00:45:44.0613338Z 2025-01-24T00:45:44.0613650Z def parse_user_opt_in_from_text(user_optin_text: str) -> UserOptins: 2025-01-24T00:45:44.0614266Z """ 2025-01-24T00:45:44.0614920Z Parse the user opt-in text into a key value pair of username and the list of features they have opted into 2025-01-24T00:45:44.0615563Z 2025-01-24T00:45:44.0616142Z Users are GitHub usernames with the @ prefix. Each user is also a comma-separated list of features/experiments to enable. 2025-01-24T00:45:44.0617060Z - Example line: "@User1,lf,split_build" 2025-01-24T00:45:44.0617696Z - A "#" prefix indicates the user is opted out of all experiments 2025-01-24T00:45:44.0618149Z 2025-01-24T00:45:44.0618154Z 2025-01-24T00:45:44.0618304Z """ 2025-01-24T00:45:44.0618647Z optins = UserOptins() 2025-01-24T00:45:44.0619098Z for user in user_optin_text.split("\n"): 2025-01-24T00:45:44.0619609Z user = user.strip("\r\n\t -") 2025-01-24T00:45:44.0620113Z if not user or not user.startswith("@"): 2025-01-24T00:45:44.0620636Z # Not a valid user. Skip 2025-01-24T00:45:44.0621086Z continue 2025-01-24T00:45:44.0621324Z 2025-01-24T00:45:44.0621478Z if user: 2025-01-24T00:45:44.0622036Z usr_name = user.split(",")[0].strip("@") 2025-01-24T00:45:44.0622699Z optins[usr_name] = [exp.strip(" ") for exp in user.split(",")[1:]] 2025-01-24T00:45:44.0623165Z 2025-01-24T00:45:44.0623320Z return optins 2025-01-24T00:45:44.0623543Z 2025-01-24T00:45:44.0623549Z 2025-01-24T00:45:44.0623819Z def is_valid_experiment_name(experiment_name: str) -> bool: 2025-01-24T00:45:44.0624508Z """ 2025-01-24T00:45:44.0624883Z Check if the experiment name is valid. 2025-01-24T00:45:44.0625375Z A valid name: 2025-01-24T00:45:44.0625962Z - Contains only alphanumeric characters and the special characters "_" & "-" 2025-01-24T00:45:44.0626845Z - The special characters "_" & "-" shouldn't be the first or last characters 2025-01-24T00:45:44.0627516Z - Cannot contain spaces 2025-01-24T00:45:44.0627945Z """ 2025-01-24T00:45:44.0628124Z 2025-01-24T00:45:44.0628369Z valid_char_regex = r"^[a-zA-Z0-9]([\w-]*[a-zA-Z0-9])?$" 2025-01-24T00:45:44.0629022Z valid = bool(re.match(valid_char_regex, experiment_name)) 2025-01-24T00:45:44.0629439Z 2025-01-24T00:45:44.0629596Z if valid: 2025-01-24T00:45:44.0629944Z return True 2025-01-24T00:45:44.0630167Z 2025-01-24T00:45:44.0630324Z log.error( 2025-01-24T00:45:44.0631671Z 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." 2025-01-24T00:45:44.0633320Z ) 2025-01-24T00:45:44.0633650Z return False 2025-01-24T00:45:44.0633871Z 2025-01-24T00:45:44.0633877Z 2025-01-24T00:45:44.0634162Z def parse_settings_from_text(settings_text: str) -> Settings: 2025-01-24T00:45:44.0634744Z """ 2025-01-24T00:45:44.0635283Z Parse the experiments from the issue body into a list of ExperimentSettings 2025-01-24T00:45:44.0635955Z """ 2025-01-24T00:45:44.0636284Z try: 2025-01-24T00:45:44.0636624Z if settings_text: 2025-01-24T00:45:44.0637434Z # Escape the backtick as well so that we can have the settings in a code block on the GH issue 2025-01-24T00:45:44.0638168Z # for easy reading 2025-01-24T00:45:44.0638897Z # Note: Using ascii for the backtick so that the cat step in _runner-determinator.yml doesn't choke on 2025-01-24T00:45:44.0639733Z # the backtick character in shell commands. 2025-01-24T00:45:44.0640299Z backtick = chr(96) # backtick character 2025-01-24T00:45:44.0640920Z settings_text = settings_text.strip(f"\r\n\t{backtick} ") 2025-01-24T00:45:44.0641533Z settings = load_yaml(settings_text) 2025-01-24T00:45:44.0642101Z 2025-01-24T00:45:44.0642516Z # For now we just load experiments. We can expand this if/when we add more settings 2025-01-24T00:45:44.0643220Z experiments = {} 2025-01-24T00:45:44.0643502Z 2025-01-24T00:45:44.0643846Z for exp_name, exp_settings in settings.get(SETTING_EXPERIMENTS).items(): 2025-01-24T00:45:44.0644570Z if not is_valid_experiment_name(exp_name): 2025-01-24T00:45:44.0645589Z # Exclude invalid experiments from the list. We log an error, but don't raise an exception so that other experiments can still be processed. 2025-01-24T00:45:44.0646580Z continue 2025-01-24T00:45:44.0646859Z 2025-01-24T00:45:44.0647030Z valid_settings = {} 2025-01-24T00:45:44.0647511Z for setting in exp_settings: 2025-01-24T00:45:44.0648035Z if setting not in Experiment._fields: 2025-01-24T00:45:44.0648551Z log.warning( 2025-01-24T00:45:44.0649212Z f"Unexpected setting in experiment: {setting} = {exp_settings[setting]}" 2025-01-24T00:45:44.0649868Z ) 2025-01-24T00:45:44.0650267Z else: 2025-01-24T00:45:44.0650746Z valid_settings[setting] = exp_settings[setting] 2025-01-24T00:45:44.0651144Z 2025-01-24T00:45:44.0651398Z experiments[exp_name] = Experiment(**valid_settings) 2025-01-24T00:45:44.0652088Z return Settings(experiments) 2025-01-24T00:45:44.0652413Z 2025-01-24T00:45:44.0652579Z except Exception: 2025-01-24T00:45:44.0653021Z log.exception("Failed to parse settings") 2025-01-24T00:45:44.0653390Z 2025-01-24T00:45:44.0653706Z return Settings() 2025-01-24T00:45:44.0653955Z 2025-01-24T00:45:44.0653961Z 2025-01-24T00:45:44.0654196Z def parse_settings(rollout_state: str) -> Settings: 2025-01-24T00:45:44.0654715Z """ 2025-01-24T00:45:44.0655115Z Parse settings, if any, from the rollout state. 2025-01-24T00:45:44.0655487Z 2025-01-24T00:45:44.0655823Z If the issue body contains "---" then the text above that is the settings 2025-01-24T00:45:44.0656511Z and the text below is the list of opted in users. 2025-01-24T00:45:44.0656896Z 2025-01-24T00:45:44.0657271Z If it doesn't contain "---" then the settings are empty and the default values are used. 2025-01-24T00:45:44.0657957Z """ 2025-01-24T00:45:44.0658495Z settings_text, _ = extract_settings_user_opt_in_from_text(rollout_state) 2025-01-24T00:45:44.0659190Z return parse_settings_from_text(settings_text) 2025-01-24T00:45:44.0659563Z 2025-01-24T00:45:44.0659570Z 2025-01-24T00:45:44.0659801Z def parse_users(rollout_state: str) -> UserOptins: 2025-01-24T00:45:44.0660324Z """ 2025-01-24T00:45:44.0660682Z Parse users from the rollout state. 2025-01-24T00:45:44.0661013Z 2025-01-24T00:45:44.0661158Z """ 2025-01-24T00:45:44.0661647Z _, users_text = extract_settings_user_opt_in_from_text(rollout_state) 2025-01-24T00:45:44.0662785Z return parse_user_opt_in_from_text(users_text) 2025-01-24T00:45:44.0663190Z 2025-01-24T00:45:44.0663197Z 2025-01-24T00:45:44.0663582Z def is_user_opted_in(user: str, user_optins: UserOptins, experiment_name: str) -> bool: 2025-01-24T00:45:44.0664270Z """ 2025-01-24T00:45:44.0664644Z Check if a user is opted into an experiment 2025-01-24T00:45:44.0665308Z """ 2025-01-24T00:45:44.0665722Z return experiment_name in user_optins.get(user, []) 2025-01-24T00:45:44.0666104Z 2025-01-24T00:45:44.0666110Z 2025-01-24T00:45:44.0666496Z def is_user_opted_out(user: str, user_optins: UserOptins, experiment_name: str) -> bool: 2025-01-24T00:45:44.0667188Z """ 2025-01-24T00:45:44.0667624Z Check if a user explicitly opted out of an experiment 2025-01-24T00:45:44.0668156Z """ 2025-01-24T00:45:44.0668735Z # if the experiment is prefixed with a "-", then it's an opt-out 2025-01-24T00:45:44.0669378Z experiment_optout = "-" + experiment_name 2025-01-24T00:45:44.0669959Z if experiment_optout not in user_optins.get(user, []): 2025-01-24T00:45:44.0670514Z return False 2025-01-24T00:45:44.0670738Z 2025-01-24T00:45:44.0670997Z if is_user_opted_in(user, user_optins, experiment_name): 2025-01-24T00:45:44.0671552Z log.warning( 2025-01-24T00:45:44.0672433Z f"User {user} is opted into experiment {experiment_name}, but also opted out of it. Defaulting to opting out" 2025-01-24T00:45:44.0673260Z ) 2025-01-24T00:45:44.0673447Z 2025-01-24T00:45:44.0673598Z return True 2025-01-24T00:45:44.0673815Z 2025-01-24T00:45:44.0673822Z 2025-01-24T00:45:44.0673984Z def get_runner_prefix( 2025-01-24T00:45:44.0674389Z rollout_state: str, 2025-01-24T00:45:44.0674820Z workflow_requestors: Iterable[str], 2025-01-24T00:45:44.0675405Z branch: str, 2025-01-24T00:45:44.0675853Z eligible_experiments: FrozenSet[str] = frozenset(), 2025-01-24T00:45:44.0676402Z is_canary: bool = False, 2025-01-24T00:45:44.0676819Z ) -> str: 2025-01-24T00:45:44.0677210Z settings = parse_settings(rollout_state) 2025-01-24T00:45:44.0677746Z user_optins = parse_users(rollout_state) 2025-01-24T00:45:44.0678095Z 2025-01-24T00:45:44.0678253Z fleet_prefix = "" 2025-01-24T00:45:44.0678639Z prefixes = [] 2025-01-24T00:45:44.0679212Z for experiment_name, experiment_settings in settings.experiments.items(): 2025-01-24T00:45:44.0680083Z if not experiment_settings.all_branches and is_exception_branch(branch): 2025-01-24T00:45:44.0680737Z log.info( 2025-01-24T00:45:44.0681356Z f"Branch {branch} is an exception branch. Not enabling experiment {experiment_name}." 2025-01-24T00:45:44.0682280Z ) 2025-01-24T00:45:44.0682771Z continue 2025-01-24T00:45:44.0683008Z 2025-01-24T00:45:44.0683187Z if eligible_experiments: 2025-01-24T00:45:44.0683699Z if experiment_name not in eligible_experiments: 2025-01-24T00:45:44.0684285Z exp_list = ", ".join(eligible_experiments) 2025-01-24T00:45:44.0684803Z log.info( 2025-01-24T00:45:44.0685519Z f"Skipping experiment '{experiment_name}', as it is not in the eligible_experiments list: {exp_list}" 2025-01-24T00:45:44.0686289Z ) 2025-01-24T00:45:44.0686657Z continue 2025-01-24T00:45:44.0687086Z elif not experiment_settings.default: 2025-01-24T00:45:44.0687588Z log.info( 2025-01-24T00:45:44.0688185Z f"Skipping experiment '{experiment_name}', as it is not a default experiment" 2025-01-24T00:45:44.0688851Z ) 2025-01-24T00:45:44.0689199Z continue 2025-01-24T00:45:44.0689424Z 2025-01-24T00:45:44.0689687Z # Is any workflow_requestor opted out to this experiment? 2025-01-24T00:45:44.0690253Z opted_out_users = [ 2025-01-24T00:45:44.0690671Z requestor 2025-01-24T00:45:44.0691087Z for requestor in workflow_requestors 2025-01-24T00:45:44.0691708Z if is_user_opted_out(requestor, user_optins, experiment_name) 2025-01-24T00:45:44.0692407Z ] 2025-01-24T00:45:44.0692603Z 2025-01-24T00:45:44.0692769Z if opted_out_users: 2025-01-24T00:45:44.0693179Z log.info( 2025-01-24T00:45:44.0693748Z f"{', '.join(opted_out_users)} have opted out of experiment {experiment_name}." 2025-01-24T00:45:44.0694526Z ) 2025-01-24T00:45:44.0694868Z continue 2025-01-24T00:45:44.0695105Z 2025-01-24T00:45:44.0695352Z # Is any workflow_requestor opted in to this experiment? 2025-01-24T00:45:44.0695926Z opted_in_users = [ 2025-01-24T00:45:44.0696333Z requestor 2025-01-24T00:45:44.0696764Z for requestor in workflow_requestors 2025-01-24T00:45:44.0697383Z if is_user_opted_in(requestor, user_optins, experiment_name) 2025-01-24T00:45:44.0697948Z ] 2025-01-24T00:45:44.0698139Z 2025-01-24T00:45:44.0698295Z enabled = False 2025-01-24T00:45:44.0698691Z if opted_in_users: 2025-01-24T00:45:44.0699095Z log.info( 2025-01-24T00:45:44.0699647Z f"{', '.join(opted_in_users)} have opted into experiment {experiment_name}." 2025-01-24T00:45:44.0700275Z ) 2025-01-24T00:45:44.0700625Z enabled = True 2025-01-24T00:45:44.0700884Z 2025-01-24T00:45:44.0701081Z elif experiment_settings.rollout_perc: 2025-01-24T00:45:44.0701960Z # If no user is opted in, then we randomly enable the experiment based on the rollout percentage 2025-01-24T00:45:44.0702813Z if random.uniform(0, 100) <= experiment_settings.rollout_perc: 2025-01-24T00:45:44.0703411Z log.info( 2025-01-24T00:45:44.0704209Z f"Based on rollout percentage of {experiment_settings.rollout_perc}%, enabling experiment {experiment_name}." 2025-01-24T00:45:44.0705052Z ) 2025-01-24T00:45:44.0705427Z enabled = True 2025-01-24T00:45:44.0705696Z 2025-01-24T00:45:44.0705849Z if enabled: 2025-01-24T00:45:44.0706225Z label = experiment_name 2025-01-24T00:45:44.0706731Z if experiment_name == LF_FLEET_EXPERIMENT: 2025-01-24T00:45:44.0707498Z # We give some special treatment to the "lf" experiment since determines the fleet we use 2025-01-24T00:45:44.0708296Z # - If it's enabled, then we always list it's prefix first 2025-01-24T00:45:44.0708996Z # - If we're in the canary branch, then we append ".c" to the lf prefix 2025-01-24T00:45:44.0709604Z if is_canary: 2025-01-24T00:45:44.0710052Z label += CANARY_FLEET_SUFFIX 2025-01-24T00:45:44.0710553Z fleet_prefix = label 2025-01-24T00:45:44.0711208Z else: 2025-01-24T00:45:44.0711608Z prefixes.append(label) 2025-01-24T00:45:44.0712049Z 2025-01-24T00:45:44.0712215Z if len(prefixes) > 1: 2025-01-24T00:45:44.0712634Z log.error( 2025-01-24T00:45:44.0713575Z 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:])}" 2025-01-24T00:45:44.0714597Z ) 2025-01-24T00:45:44.0714955Z prefixes = prefixes[:1] 2025-01-24T00:45:44.0715237Z 2025-01-24T00:45:44.0715409Z # Fleet always comes first 2025-01-24T00:45:44.0715847Z if fleet_prefix: 2025-01-24T00:45:44.0716268Z prefixes.insert(0, fleet_prefix) 2025-01-24T00:45:44.0716599Z 2025-01-24T00:45:44.0716819Z return ".".join(prefixes) + "." if prefixes else "" 2025-01-24T00:45:44.0717204Z 2025-01-24T00:45:44.0717211Z 2025-01-24T00:45:44.0717623Z def get_rollout_state_from_issue(github_token: str, repo: str, issue_num: int) -> str: 2025-01-24T00:45:44.0718331Z """ 2025-01-24T00:45:44.0718870Z Gets the first comment of the issue, which contains the desired rollout state. 2025-01-24T00:45:44.0719385Z 2025-01-24T00:45:44.0719739Z The default issue we use - https://github.com/pytorch/test-infra/issues/5132 2025-01-24T00:45:44.0720386Z """ 2025-01-24T00:45:44.0720739Z gh = get_gh_client(github_token) 2025-01-24T00:45:44.0721233Z issue = get_issue(gh, repo, issue_num) 2025-01-24T00:45:44.0721992Z return str(issue.get_comments()[0].body.strip("\n\t ")) 2025-01-24T00:45:44.0722450Z 2025-01-24T00:45:44.0722459Z 2025-01-24T00:45:44.0722836Z def download_json(url: str, headers: Dict[str, str], num_retries: int = 3) -> Any: 2025-01-24T00:45:44.0723670Z for _ in range(num_retries): 2025-01-24T00:45:44.0724112Z try: 2025-01-24T00:45:44.0724510Z req = Request(url=url, headers=headers) 2025-01-24T00:45:44.0725113Z content = urlopen(req, timeout=5).read().decode("utf-8") 2025-01-24T00:45:44.0725712Z return json.loads(content) 2025-01-24T00:45:44.0726195Z except Exception as e: 2025-01-24T00:45:44.0726689Z log.warning(f"Could not download {url}: {e}") 2025-01-24T00:45:44.0727065Z 2025-01-24T00:45:44.0727414Z log.warning(f"All {num_retries} retries exhausted, downloading {url} failed") 2025-01-24T00:45:44.0728065Z return {} 2025-01-24T00:45:44.0728265Z 2025-01-24T00:45:44.0728271Z 2025-01-24T00:45:44.0728440Z @lru_cache(maxsize=None) 2025-01-24T00:45:44.0729081Z def get_pr_info(github_repo: str, github_token: str, pr_number: int) -> Dict[str, Any]: 2025-01-24T00:45:44.0729766Z """ 2025-01-24T00:45:44.0730122Z Dynamically get PR information 2025-01-24T00:45:44.0730573Z """ 2025-01-24T00:45:44.0731020Z github_api = f"https://api.github.com/repos/{github_repo}" 2025-01-24T00:45:44.0731588Z headers = { 2025-01-24T00:45:44.0732120Z "Accept": "application/vnd.github.v3+json", 2025-01-24T00:45:44.0732683Z "Authorization": f"token {github_token}", 2025-01-24T00:45:44.0733173Z } 2025-01-24T00:45:44.0733568Z json_response: Dict[str, Any] = download_json( 2025-01-24T00:45:44.0734123Z url=f"{github_api}/issues/{pr_number}", 2025-01-24T00:45:44.0734619Z headers=headers, 2025-01-24T00:45:44.0735015Z ) 2025-01-24T00:45:44.0735195Z 2025-01-24T00:45:44.0735368Z if not json_response: 2025-01-24T00:45:44.0735882Z log.warning(f"Failed to get the labels for #{pr_number}") 2025-01-24T00:45:44.0736447Z return {} 2025-01-24T00:45:44.0736659Z 2025-01-24T00:45:44.0736831Z return json_response 2025-01-24T00:45:44.0737087Z 2025-01-24T00:45:44.0737093Z 2025-01-24T00:45:44.0737458Z def get_labels(github_repo: str, github_token: str, pr_number: int) -> Set[str]: 2025-01-24T00:45:44.0738132Z """ 2025-01-24T00:45:44.0738608Z Dynamically get the latest list of labels from the pull request 2025-01-24T00:45:44.0739195Z """ 2025-01-24T00:45:44.0739769Z pr_info = get_pr_info(github_repo, github_token, pr_number) 2025-01-24T00:45:44.0740343Z return { 2025-01-24T00:45:44.0740869Z label.get("name") for label in pr_info.get("labels", []) if label.get("name") 2025-01-24T00:45:44.0741509Z } 2025-01-24T00:45:44.0741692Z 2025-01-24T00:45:44.0741704Z 2025-01-24T00:45:44.0741966Z def main() -> None: 2025-01-24T00:45:44.0742352Z args = parse_args() 2025-01-24T00:45:44.0742605Z 2025-01-24T00:45:44.0742805Z runner_label_prefix = DEFAULT_LABEL_PREFIX 2025-01-24T00:45:44.0743158Z 2025-01-24T00:45:44.0743329Z # Check if the PR is opt-out 2025-01-24T00:45:44.0743777Z if args.pr_number: 2025-01-24T00:45:44.0744371Z labels = get_labels(args.github_repo, args.github_token, int(args.pr_number)) 2025-01-24T00:45:44.0745062Z if OPT_OUT_LABEL in labels: 2025-01-24T00:45:44.0745515Z log.info( 2025-01-24T00:45:44.0746143Z f"Opt-out runner determinator because #{args.pr_number} has {OPT_OUT_LABEL} label" 2025-01-24T00:45:44.0746882Z ) 2025-01-24T00:45:44.0747381Z set_github_output(GH_OUTPUT_KEY_LABEL_TYPE, runner_label_prefix) 2025-01-24T00:45:44.0747988Z sys.exit() 2025-01-24T00:45:44.0748230Z 2025-01-24T00:45:44.0748376Z try: 2025-01-24T00:45:44.0748774Z rollout_state = get_rollout_state_from_issue( 2025-01-24T00:45:44.0749413Z args.github_token, args.github_issue_repo, args.github_issue 2025-01-24T00:45:44.0749995Z ) 2025-01-24T00:45:44.0750183Z 2025-01-24T00:45:44.0750373Z username = get_potential_pr_author( 2025-01-24T00:45:44.0750865Z args.github_token, 2025-01-24T00:45:44.0751440Z args.github_repo, 2025-01-24T00:45:44.0751976Z args.github_actor, 2025-01-24T00:45:44.0752416Z args.github_ref_type, 2025-01-24T00:45:44.0752869Z args.github_branch, 2025-01-24T00:45:44.0753290Z ) 2025-01-24T00:45:44.0753481Z 2025-01-24T00:45:44.0753744Z is_canary = args.github_repo == "pytorch/pytorch-canary" 2025-01-24T00:45:44.0754158Z 2025-01-24T00:45:44.0754352Z runner_label_prefix = get_runner_prefix( 2025-01-24T00:45:44.0754861Z rollout_state, 2025-01-24T00:45:44.0755300Z (args.github_issue_owner, username), 2025-01-24T00:45:44.0755804Z args.github_branch, 2025-01-24T00:45:44.0756256Z args.eligible_experiments, 2025-01-24T00:45:44.0756736Z is_canary, 2025-01-24T00:45:44.0757113Z ) 2025-01-24T00:45:44.0757297Z 2025-01-24T00:45:44.0757474Z except Exception as e: 2025-01-24T00:45:44.0757887Z log.error( 2025-01-24T00:45:44.0758497Z f"Failed to get issue. Defaulting to Meta runners and no experiments. Exception: {e}" 2025-01-24T00:45:44.0759203Z ) 2025-01-24T00:45:44.0759385Z 2025-01-24T00:45:44.0759684Z set_github_output(GH_OUTPUT_KEY_LABEL_TYPE, runner_label_prefix) 2025-01-24T00:45:44.0760144Z 2025-01-24T00:45:44.0760150Z 2025-01-24T00:45:44.0760309Z if __name__ == "__main__": 2025-01-24T00:45:44.0760713Z main() 2025-01-24T00:45:44.0760903Z 2025-01-24T00:45:44.0847173Z ##[group]Run python3 -m pip install urllib3==1.26.18 PyGithub==2.3.0 2025-01-24T00:45:44.0848015Z python3 -m pip install urllib3==1.26.18 PyGithub==2.3.0 2025-01-24T00:45:44.0876121Z shell: /usr/bin/bash -e {0} 2025-01-24T00:45:44.0876570Z env: 2025-01-24T00:45:44.0877132Z GITHUB_TOKEN: *** 2025-01-24T00:45:44.0877519Z ISSUE_NUMBER: 5132 2025-01-24T00:45:44.0877941Z TRIGGERING_ACTOR: pytorch-bot[bot] 2025-01-24T00:45:44.0878415Z ISSUE_OWNER: 2025-01-24T00:45:44.0878790Z CHECK_EXPERIMENTS: 2025-01-24T00:45:44.0879188Z PR_NUMBER: 2025-01-24T00:45:44.0879565Z ##[endgroup] 2025-01-24T00:45:44.5577561Z Defaulting to user installation because normal site-packages is not writeable 2025-01-24T00:45:45.0272648Z Collecting urllib3==1.26.18 2025-01-24T00:45:45.0890857Z Downloading urllib3-1.26.18-py2.py3-none-any.whl.metadata (48 kB) 2025-01-24T00:45:45.1181193Z ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 48.9/48.9 kB 2.5 MB/s eta 0:00:00 2025-01-24T00:45:45.1457538Z Collecting PyGithub==2.3.0 2025-01-24T00:45:45.1591235Z Downloading PyGithub-2.3.0-py3-none-any.whl.metadata (3.8 kB) 2025-01-24T00:45:45.2130232Z Collecting pynacl>=1.4.0 (from PyGithub==2.3.0) 2025-01-24T00:45:45.2263897Z Downloading PyNaCl-1.5.0-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl.metadata (8.6 kB) 2025-01-24T00:45:45.2324453Z Requirement already satisfied: requests>=2.14.0 in /usr/lib/python3/dist-packages (from PyGithub==2.3.0) (2.31.0) 2025-01-24T00:45:45.2340834Z Requirement already satisfied: pyjwt>=2.4.0 in /usr/lib/python3/dist-packages (from pyjwt[crypto]>=2.4.0->PyGithub==2.3.0) (2.7.0) 2025-01-24T00:45:45.2355211Z Requirement already satisfied: typing-extensions>=4.0.0 in /usr/lib/python3/dist-packages (from PyGithub==2.3.0) (4.10.0) 2025-01-24T00:45:45.2633990Z Collecting Deprecated (from PyGithub==2.3.0) 2025-01-24T00:45:45.2759183Z Downloading Deprecated-1.2.15-py2.py3-none-any.whl.metadata (5.5 kB) 2025-01-24T00:45:45.2997223Z Requirement already satisfied: cryptography>=3.4.0 in /usr/lib/python3/dist-packages (from pyjwt[crypto]>=2.4.0->PyGithub==2.3.0) (41.0.7) 2025-01-24T00:45:45.4259477Z Collecting cffi>=1.4.1 (from pynacl>=1.4.0->PyGithub==2.3.0) 2025-01-24T00:45:45.4394432Z Downloading cffi-1.17.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (1.5 kB) 2025-01-24T00:45:45.5529525Z Collecting wrapt<2,>=1.10 (from Deprecated->PyGithub==2.3.0) 2025-01-24T00:45:45.5774279Z Downloading wrapt-1.17.2-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (6.4 kB) 2025-01-24T00:45:45.6127744Z Collecting pycparser (from cffi>=1.4.1->pynacl>=1.4.0->PyGithub==2.3.0) 2025-01-24T00:45:45.6271191Z Downloading pycparser-2.22-py3-none-any.whl.metadata (943 bytes) 2025-01-24T00:45:45.6729263Z Downloading urllib3-1.26.18-py2.py3-none-any.whl (143 kB) 2025-01-24T00:45:45.6905388Z ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 143.8/143.8 kB 8.9 MB/s eta 0:00:00 2025-01-24T00:45:45.7060781Z Downloading PyGithub-2.3.0-py3-none-any.whl (354 kB) 2025-01-24T00:45:45.7295104Z ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 354.4/354.4 kB 16.4 MB/s eta 0:00:00 2025-01-24T00:45:45.7429908Z Downloading PyNaCl-1.5.0-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl (856 kB) 2025-01-24T00:45:45.7624834Z ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 856.7/856.7 kB 49.8 MB/s eta 0:00:00 2025-01-24T00:45:45.7749578Z Downloading Deprecated-1.2.15-py2.py3-none-any.whl (9.9 kB) 2025-01-24T00:45:45.7923121Z Downloading cffi-1.17.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (479 kB) 2025-01-24T00:45:45.8047185Z ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 479.4/479.4 kB 43.4 MB/s eta 0:00:00 2025-01-24T00:45:45.8182386Z Downloading wrapt-1.17.2-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl (89 kB) 2025-01-24T00:45:45.8233134Z ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 89.2/89.2 kB 22.7 MB/s eta 0:00:00 2025-01-24T00:45:45.8358579Z Downloading pycparser-2.22-py3-none-any.whl (117 kB) 2025-01-24T00:45:45.8419344Z ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 117.6/117.6 kB 25.1 MB/s eta 0:00:00 2025-01-24T00:45:46.1320896Z Installing collected packages: wrapt, urllib3, pycparser, Deprecated, cffi, pynacl, PyGithub 2025-01-24T00:45:46.6626579Z Successfully installed Deprecated-1.2.15 PyGithub-2.3.0 cffi-1.17.1 pycparser-2.22 pynacl-1.5.0 urllib3-1.26.18 wrapt-1.17.2 2025-01-24T00:45:46.7339205Z ##[group]Run curr_branch="ciflow/inductor/145539" 2025-01-24T00:45:46.7339656Z curr_branch="ciflow/inductor/145539" 2025-01-24T00:45:46.7340013Z curr_ref_type="tag" 2025-01-24T00:45:46.7340311Z echo "Current branch is '$curr_branch'" 2025-01-24T00:45:46.7340609Z  2025-01-24T00:45:46.7340856Z python3 runner_determinator.py \ 2025-01-24T00:45:46.7341191Z  --github-token "$GITHUB_TOKEN" \ 2025-01-24T00:45:46.7341505Z  --github-issue "$ISSUE_NUMBER" \ 2025-01-24T00:45:46.7341976Z  --github-branch "$curr_branch" \ 2025-01-24T00:45:46.7342300Z  --github-actor "$TRIGGERING_ACTOR" \ 2025-01-24T00:45:46.7342629Z  --github-issue-owner "$ISSUE_OWNER" \ 2025-01-24T00:45:46.7342964Z  --github-ref-type "$curr_ref_type" \ 2025-01-24T00:45:46.7343309Z  --github-repo "$GITHUB_REPOSITORY" \ 2025-01-24T00:45:46.7343706Z  --eligible-experiments "$CHECK_EXPERIMENTS" \ 2025-01-24T00:45:46.7344088Z  --pr-number "${PR_NUMBER}" 2025-01-24T00:45:46.7372376Z shell: /usr/bin/bash -e {0} 2025-01-24T00:45:46.7372669Z env: 2025-01-24T00:45:46.7373307Z GITHUB_TOKEN: *** 2025-01-24T00:45:46.7373551Z ISSUE_NUMBER: 5132 2025-01-24T00:45:46.7373805Z TRIGGERING_ACTOR: pytorch-bot[bot] 2025-01-24T00:45:46.7374091Z ISSUE_OWNER: 2025-01-24T00:45:46.7374309Z CHECK_EXPERIMENTS: 2025-01-24T00:45:46.7374551Z PR_NUMBER: 2025-01-24T00:45:46.7374768Z ##[endgroup] 2025-01-24T00:45:46.7423031Z Current branch is 'ciflow/inductor/145539' 2025-01-24T00:45:49.1228975Z INFO : Based on rollout percentage of 55%, enabling experiment lf. 2025-01-24T00:45:49.1230363Z INFO : Skipping experiment 'awsa100', as it is not a default experiment 2025-01-24T00:45:49.1231251Z INFO : Setting output: label-type='lf.' 2025-01-24T00:45:49.1535541Z Evaluate and set job outputs 2025-01-24T00:45:49.1542425Z Set output 'label-type' 2025-01-24T00:45:49.1544549Z Cleaning up orphan processes