2024-12-17T23:28:40.2446587Z Current runner version: '2.321.0' 2024-12-17T23:28:40.2469380Z ##[group]Operating System 2024-12-17T23:28:40.2470236Z Ubuntu 2024-12-17T23:28:40.2470731Z 22.04.5 2024-12-17T23:28:40.2471194Z LTS 2024-12-17T23:28:40.2471745Z ##[endgroup] 2024-12-17T23:28:40.2472282Z ##[group]Runner Image 2024-12-17T23:28:40.2472804Z Image: ubuntu-22.04 2024-12-17T23:28:40.2473388Z Version: 20241211.1.0 2024-12-17T23:28:40.2474409Z Included Software: https://github.com/actions/runner-images/blob/ubuntu22/20241211.1/images/ubuntu/Ubuntu2204-Readme.md 2024-12-17T23:28:40.2475714Z Image Release: https://github.com/actions/runner-images/releases/tag/ubuntu22%2F20241211.1 2024-12-17T23:28:40.2476670Z ##[endgroup] 2024-12-17T23:28:40.2477207Z ##[group]Runner Image Provisioner 2024-12-17T23:28:40.2477767Z 2.0.404.1 2024-12-17T23:28:40.2478283Z ##[endgroup] 2024-12-17T23:28:40.2480355Z ##[group]GITHUB_TOKEN Permissions 2024-12-17T23:28:40.2482317Z Actions: read 2024-12-17T23:28:40.2483089Z Attestations: read 2024-12-17T23:28:40.2483728Z Checks: read 2024-12-17T23:28:40.2484234Z Contents: read 2024-12-17T23:28:40.2484712Z Deployments: read 2024-12-17T23:28:40.2485294Z Discussions: read 2024-12-17T23:28:40.2485791Z Issues: read 2024-12-17T23:28:40.2486255Z Metadata: read 2024-12-17T23:28:40.2486807Z Packages: read 2024-12-17T23:28:40.2487301Z Pages: read 2024-12-17T23:28:40.2487762Z PullRequests: read 2024-12-17T23:28:40.2488339Z RepositoryProjects: read 2024-12-17T23:28:40.2488892Z SecurityEvents: read 2024-12-17T23:28:40.2489388Z Statuses: read 2024-12-17T23:28:40.2489942Z ##[endgroup] 2024-12-17T23:28:40.2492684Z Secret source: Actions 2024-12-17T23:28:40.2493424Z Prepare workflow directory 2024-12-17T23:28:40.2969414Z Prepare all required actions 2024-12-17T23:28:40.3023454Z Uses: pytorch/pytorch/.github/workflows/_runner-determinator.yml@refs/heads/release/2.6 (0cdf8b1d09254cfda66191d1bd01e3041c3c76f7) 2024-12-17T23:28:40.3028405Z ##[group] Inputs 2024-12-17T23:28:40.3029003Z check_experiments: 2024-12-17T23:28:40.3029545Z triggering_actor: malfet 2024-12-17T23:28:40.3030238Z issue_owner: 2024-12-17T23:28:40.3030749Z curr_branch: release/2.6 2024-12-17T23:28:40.3031269Z curr_ref_type: branch 2024-12-17T23:28:40.3031899Z issue_number: 5132 2024-12-17T23:28:40.3032430Z ##[endgroup] 2024-12-17T23:28:40.3033036Z Complete job name: unit-test / get-label-type / runner-determinator 2024-12-17T23:28:40.3676501Z ##[group]Run cat < runner_determinator.py 2024-12-17T23:28:40.3678817Z cat < runner_determinator.py 2024-12-17T23:28:40.3679515Z # flake8: noqa: G004 2024-12-17T23:28:40.3680043Z  2024-12-17T23:28:40.3680851Z # Note: Copies of this script in runner_determinator.py and _runner-determinator.yml 2024-12-17T23:28:40.3681911Z # must be kept in sync. You can do it easily by running the following command: 2024-12-17T23:28:40.3682807Z # python .github/scripts/update_runner_determinator.py 2024-12-17T23:28:40.3683614Z  2024-12-17T23:28:40.3684116Z """ 2024-12-17T23:28:40.3684813Z This runner determinator is used to determine which set of runners to run a 2024-12-17T23:28:40.3685830Z GitHub job on. It uses the first comment of a GitHub issue (by default 2024-12-17T23:28:40.3687182Z https://github.com/pytorch/test-infra/issues/5132) to define the configuration 2024-12-17T23:28:40.3688096Z of which runners should be used to run which job. 2024-12-17T23:28:40.3688873Z  2024-12-17T23:28:40.3689556Z The configuration has two parts, the settings and a list of opted-in users, 2024-12-17T23:28:40.3690629Z separated by a line containing "---". If the line is not present, the 2024-12-17T23:28:40.3691735Z settings are considered to be empty with only the second part, the user 2024-12-17T23:28:40.3692569Z list, defined. 2024-12-17T23:28:40.3693249Z  2024-12-17T23:28:40.3693982Z The first part is a YAML block that defines the rollout settings. This can be 2024-12-17T23:28:40.3695911Z used to define any settings that are needed to determine which runners to use. 2024-12-17T23:28:40.3696987Z It's fields are defined by the RolloutSettings class below. 2024-12-17T23:28:40.3697692Z  2024-12-17T23:28:40.3698431Z The second part is a list of users who are explicitly opted in to the LF fleet. 2024-12-17T23:28:40.3699543Z The user list is also a comma separated list of additional features or 2024-12-17T23:28:40.3700482Z experiments which the user could be opted in to. 2024-12-17T23:28:40.3701119Z  2024-12-17T23:28:40.3701679Z The user list has the following rules: 2024-12-17T23:28:40.3702435Z  2024-12-17T23:28:40.3703030Z - Users are GitHub usernames, which must start with the @ prefix 2024-12-17T23:28:40.3704772Z - Each user is also a comma-separated list of features/experiments to enable 2024-12-17T23:28:40.3705819Z - A "#" prefix opts the user out of all experiments 2024-12-17T23:28:40.3706446Z  2024-12-17T23:28:40.3707000Z Example config: 2024-12-17T23:28:40.3707655Z  # A list of experiments that can be opted into. 2024-12-17T23:28:40.3708528Z  # This defines the behavior they'll induce when opted into. 2024-12-17T23:28:40.3709341Z  # Expected syntax is: 2024-12-17T23:28:40.3710165Z  # [experiment_name]: # Name of the experiment. Also used for the label prefix. 2024-12-17T23:28:40.3711274Z  # rollout_perc: [int] # % of workflows to run with this experiment when users are not opted in. 2024-12-17T23:28:40.3712152Z  2024-12-17T23:28:40.3712635Z  experiments: 2024-12-17T23:28:40.3713181Z  lf: 2024-12-17T23:28:40.3713706Z  rollout_percent: 25 2024-12-17T23:28:40.3714332Z  all_branches: false 2024-12-17T23:28:40.3714930Z  default: true 2024-12-17T23:28:40.3715499Z  --- 2024-12-17T23:28:40.3716019Z  2024-12-17T23:28:40.3716475Z  # Opt-ins: 2024-12-17T23:28:40.3717230Z  # Users can opt into the LF fleet by adding their GitHub username to this list 2024-12-17T23:28:40.3718483Z  # and specifying experiments to enable in a comma-separated list. 2024-12-17T23:28:40.3719413Z  # To always opt out of an experiment, prefix it with a "-". 2024-12-17T23:28:40.3720287Z  # Experiments should be from the above list. 2024-12-17T23:28:40.3720909Z  2024-12-17T23:28:40.3721449Z  @User1,-lf,split_build 2024-12-17T23:28:40.3722125Z  @User2,lf 2024-12-17T23:28:40.3722622Z  @User3,split_build 2024-12-17T23:28:40.3723173Z """ 2024-12-17T23:28:40.3723722Z  2024-12-17T23:28:40.3724142Z import json 2024-12-17T23:28:40.3725042Z import logging 2024-12-17T23:28:40.3726059Z import os 2024-12-17T23:28:40.3726827Z import random 2024-12-17T23:28:40.3727691Z import re 2024-12-17T23:28:40.3728589Z import sys 2024-12-17T23:28:40.3729116Z from argparse import ArgumentParser 2024-12-17T23:28:40.3729769Z from functools import lru_cache 2024-12-17T23:28:40.3730498Z from logging import LogRecord 2024-12-17T23:28:40.3731338Z from typing import Any, Dict, FrozenSet, Iterable, List, NamedTuple, Set, Tuple 2024-12-17T23:28:40.3732230Z from urllib.request import Request, urlopen 2024-12-17T23:28:40.3732954Z  2024-12-17T23:28:40.3733414Z import yaml 2024-12-17T23:28:40.3733929Z from github import Auth, Github 2024-12-17T23:28:40.3734616Z from github.Issue import Issue 2024-12-17T23:28:40.3735442Z  2024-12-17T23:28:40.3735920Z  2024-12-17T23:28:40.3736545Z DEFAULT_LABEL_PREFIX = "" # use meta runners 2024-12-17T23:28:40.3737619Z WORKFLOW_LABEL_LF = "lf." # use runners from the linux foundation 2024-12-17T23:28:40.3738579Z WORKFLOW_LABEL_LF_CANARY = "lf.c." # use canary runners from the linux foundation 2024-12-17T23:28:40.3739473Z  2024-12-17T23:28:40.3740028Z GITHUB_OUTPUT = os.getenv("GITHUB_OUTPUT", "") 2024-12-17T23:28:40.3740693Z GH_OUTPUT_KEY_AMI = "runner-ami" 2024-12-17T23:28:40.3741433Z GH_OUTPUT_KEY_LABEL_TYPE = "label-type" 2024-12-17T23:28:40.3742140Z OPT_OUT_LABEL = "no-runner-experiments" 2024-12-17T23:28:40.3742735Z  2024-12-17T23:28:40.3743297Z SETTING_EXPERIMENTS = "experiments" 2024-12-17T23:28:40.3743921Z  2024-12-17T23:28:40.3744362Z LF_FLEET_EXPERIMENT = "lf" 2024-12-17T23:28:40.3745016Z CANARY_FLEET_SUFFIX = ".c" 2024-12-17T23:28:40.3745602Z  2024-12-17T23:28:40.3746216Z  2024-12-17T23:28:40.3747196Z class Experiment(NamedTuple): 2024-12-17T23:28:40.3748361Z  rollout_perc: float = ( 2024-12-17T23:28:40.3749342Z  0 # Percentage of workflows to experiment on when user is not opted-in. 2024-12-17T23:28:40.3750235Z  ) 2024-12-17T23:28:40.3750729Z  all_branches: bool = ( 2024-12-17T23:28:40.3751508Z  False # If True, the experiment is also enabled on the exception branches 2024-12-17T23:28:40.3752359Z  ) 2024-12-17T23:28:40.3752843Z  default: bool = ( 2024-12-17T23:28:40.3753545Z  True # If True, the experiment is enabled by default for all queries 2024-12-17T23:28:40.3754363Z  ) 2024-12-17T23:28:40.3754850Z  2024-12-17T23:28:40.3755322Z  # Add more fields as needed 2024-12-17T23:28:40.3755981Z  2024-12-17T23:28:40.3756430Z  2024-12-17T23:28:40.3756932Z class Settings(NamedTuple): 2024-12-17T23:28:40.3757561Z  """ 2024-12-17T23:28:40.3758179Z  Settings for the experiments that can be opted into. 2024-12-17T23:28:40.3758871Z  """ 2024-12-17T23:28:40.3759386Z  2024-12-17T23:28:40.3759901Z  experiments: Dict[str, Experiment] = {} 2024-12-17T23:28:40.3760506Z  2024-12-17T23:28:40.3761403Z  2024-12-17T23:28:40.3762156Z class ColorFormatter(logging.Formatter): 2024-12-17T23:28:40.3762959Z  """Color codes the log messages based on the log level""" 2024-12-17T23:28:40.3763713Z  2024-12-17T23:28:40.3764202Z  COLORS = { 2024-12-17T23:28:40.3764738Z  "WARNING": "\033[33m", # Yellow 2024-12-17T23:28:40.3765417Z  "ERROR": "\033[31m", # Red 2024-12-17T23:28:40.3766061Z  "CRITICAL": "\033[31m", # Red 2024-12-17T23:28:40.3766675Z  "INFO": "\033[0m", # Reset 2024-12-17T23:28:40.3767373Z  "DEBUG": "\033[0m", # Reset 2024-12-17T23:28:40.3767968Z  } 2024-12-17T23:28:40.3768417Z  2024-12-17T23:28:40.3769036Z  def format(self, record: LogRecord) -> str: 2024-12-17T23:28:40.3769911Z  log_color = self.COLORS.get(record.levelname, "\033[0m") # Default to reset 2024-12-17T23:28:40.3770793Z  record.msg = f"{log_color}{record.msg}\033[0m" 2024-12-17T23:28:40.3771605Z  return super().format(record) 2024-12-17T23:28:40.3772189Z  2024-12-17T23:28:40.3772615Z  2024-12-17T23:28:40.3773209Z handler = logging.StreamHandler() 2024-12-17T23:28:40.3774038Z handler.setFormatter(ColorFormatter(fmt="%(levelname)-8s: %(message)s")) 2024-12-17T23:28:40.3774844Z  2024-12-17T23:28:40.3775829Z log = logging.getLogger(os.path.basename(__file__)) 2024-12-17T23:28:40.3776538Z log.addHandler(handler) 2024-12-17T23:28:40.3777117Z log.setLevel(logging.INFO) 2024-12-17T23:28:40.3777818Z  2024-12-17T23:28:40.3778428Z  2024-12-17T23:28:40.3778981Z def set_github_output(key: str, value: str) -> None: 2024-12-17T23:28:40.3779785Z  """ 2024-12-17T23:28:40.3780396Z  Defines outputs of the github action that invokes this script 2024-12-17T23:28:40.3781136Z  """ 2024-12-17T23:28:40.3781741Z  if not GITHUB_OUTPUT: 2024-12-17T23:28:40.3782937Z  # See https://github.blog/changelog/2022-10-11-github-actions-deprecating-save-state-and-set-output-commands/ for deprecation notice 2024-12-17T23:28:40.3784150Z  log.warning( 2024-12-17T23:28:40.3785255Z  "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:40.3786286Z  ) 2024-12-17T23:28:40.3786826Z  print(f"::set-output name={key}::{value}") 2024-12-17T23:28:40.3787580Z  return 2024-12-17T23:28:40.3788113Z  2024-12-17T23:28:40.3788563Z  with open(GITHUB_OUTPUT, "a") as f: 2024-12-17T23:28:40.3789349Z  log.info(f"Setting output: {key}='{value}'") 2024-12-17T23:28:40.3790049Z  f.write(f"{key}={value}\n") 2024-12-17T23:28:40.3790689Z  2024-12-17T23:28:40.3791121Z  2024-12-17T23:28:40.3791764Z def _str_comma_separated_to_set(value: str) -> FrozenSet[str]: 2024-12-17T23:28:40.3792570Z  return frozenset( 2024-12-17T23:28:40.3793311Z  filter(lambda itm: itm != "", map(str.strip, value.strip(" \n\t").split(","))) 2024-12-17T23:28:40.3794114Z  ) 2024-12-17T23:28:40.3794842Z  2024-12-17T23:28:40.3795692Z  2024-12-17T23:28:40.3796465Z def parse_args() -> Any: 2024-12-17T23:28:40.3797694Z  parser = ArgumentParser("Get dynamic rollout settings") 2024-12-17T23:28:40.3799344Z  parser.add_argument("--github-token", type=str, required=True, help="GitHub token") 2024-12-17T23:28:40.3800863Z  parser.add_argument( 2024-12-17T23:28:40.3801892Z  "--github-issue-repo", 2024-12-17T23:28:40.3802877Z  type=str, 2024-12-17T23:28:40.3803760Z  required=False, 2024-12-17T23:28:40.3805023Z  default="pytorch/test-infra", 2024-12-17T23:28:40.3806148Z  help="GitHub repo to get the issue", 2024-12-17T23:28:40.3807223Z  ) 2024-12-17T23:28:40.3808081Z  parser.add_argument( 2024-12-17T23:28:40.3809086Z  "--github-repo", 2024-12-17T23:28:40.3810039Z  type=str, 2024-12-17T23:28:40.3811044Z  required=True, 2024-12-17T23:28:40.3812057Z  help="GitHub repo where CI is running", 2024-12-17T23:28:40.3813136Z  ) 2024-12-17T23:28:40.3814028Z  parser.add_argument( 2024-12-17T23:28:40.3815656Z  "--github-issue", type=int, required=True, help="GitHub issue number" 2024-12-17T23:28:40.3816952Z  ) 2024-12-17T23:28:40.3817855Z  parser.add_argument( 2024-12-17T23:28:40.3819165Z  "--github-actor", type=str, required=True, help="GitHub triggering_actor" 2024-12-17T23:28:40.3820643Z  ) 2024-12-17T23:28:40.3821517Z  parser.add_argument( 2024-12-17T23:28:40.3822729Z  "--github-issue-owner", type=str, required=True, help="GitHub issue owner" 2024-12-17T23:28:40.3823661Z  ) 2024-12-17T23:28:40.3824168Z  parser.add_argument( 2024-12-17T23:28:40.3824933Z  "--github-branch", type=str, required=True, help="Current GitHub branch or tag" 2024-12-17T23:28:40.3825837Z  ) 2024-12-17T23:28:40.3826336Z  parser.add_argument( 2024-12-17T23:28:40.3826894Z  "--github-ref-type", 2024-12-17T23:28:40.3827554Z  type=str, 2024-12-17T23:28:40.3828453Z  required=True, 2024-12-17T23:28:40.3829536Z  help="Current GitHub ref type, branch or tag", 2024-12-17T23:28:40.3830822Z  ) 2024-12-17T23:28:40.3831344Z  parser.add_argument( 2024-12-17T23:28:40.3831939Z  "--eligible-experiments", 2024-12-17T23:28:40.3832700Z  type=_str_comma_separated_to_set, 2024-12-17T23:28:40.3833334Z  required=False, 2024-12-17T23:28:40.3833879Z  default="", 2024-12-17T23:28:40.3834926Z  help="comma separated list of experiments to check, if omitted all experiments marked with default=True are checked", 2024-12-17T23:28:40.3835935Z  ) 2024-12-17T23:28:40.3836420Z  parser.add_argument( 2024-12-17T23:28:40.3837046Z  "--pr-number", 2024-12-17T23:28:40.3837617Z  type=str, 2024-12-17T23:28:40.3838147Z  required=False, 2024-12-17T23:28:40.3838743Z  default="", 2024-12-17T23:28:40.3839405Z  help="the optional PR number where this is run", 2024-12-17T23:28:40.3840067Z  ) 2024-12-17T23:28:40.3840586Z  2024-12-17T23:28:40.3841083Z  return parser.parse_args() 2024-12-17T23:28:40.3841660Z  2024-12-17T23:28:40.3842151Z  2024-12-17T23:28:40.3842716Z def get_gh_client(github_token: str) -> Github: 2024-12-17T23:28:40.3843394Z  auth = Auth.Token(github_token) 2024-12-17T23:28:40.3844054Z  return Github(auth=auth) 2024-12-17T23:28:40.3844641Z  2024-12-17T23:28:40.3845057Z  2024-12-17T23:28:40.3845714Z def get_issue(gh: Github, repo: str, issue_num: int) -> Issue: 2024-12-17T23:28:40.3846496Z  repo = gh.get_repo(repo) 2024-12-17T23:28:40.3847328Z  return repo.get_issue(number=issue_num) 2024-12-17T23:28:40.3848606Z  2024-12-17T23:28:40.3849404Z  2024-12-17T23:28:40.3850369Z def get_potential_pr_author( 2024-12-17T23:28:40.3851712Z  github_token: str, repo: str, username: str, ref_type: str, ref_name: str 2024-12-17T23:28:40.3853096Z ) -> str: 2024-12-17T23:28:40.3854274Z  # If the trigger was a new tag added by a bot, this is a ciflow case 2024-12-17T23:28:40.3855820Z  # Fetch the actual username from the original PR. The PR number is 2024-12-17T23:28:40.3857122Z  # embedded in the tag name: ciflow// 2024-12-17T23:28:40.3857851Z  2024-12-17T23:28:40.3858391Z  gh = get_gh_client(github_token) 2024-12-17T23:28:40.3859099Z  2024-12-17T23:28:40.3859674Z  if username == "pytorch-bot[bot]" and ref_type == "tag": 2024-12-17T23:28:40.3860403Z  split_tag = ref_name.split("/") 2024-12-17T23:28:40.3861105Z  if ( 2024-12-17T23:28:40.3861611Z  len(split_tag) == 3 2024-12-17T23:28:40.3862230Z  and split_tag[0] == "ciflow" 2024-12-17T23:28:40.3862956Z  and split_tag[2].isnumeric() 2024-12-17T23:28:40.3863547Z  ): 2024-12-17T23:28:40.3864058Z  pr_number = split_tag[2] 2024-12-17T23:28:40.3864736Z  try: 2024-12-17T23:28:40.3865307Z  repository = gh.get_repo(repo) 2024-12-17T23:28:40.3866060Z  pull = repository.get_pull(number=int(pr_number)) 2024-12-17T23:28:40.3867041Z  except Exception as e: 2024-12-17T23:28:40.3867823Z  raise Exception( # noqa: TRY002 2024-12-17T23:28:40.3868610Z  f"issue with pull request {pr_number} from repo {repository}" 2024-12-17T23:28:40.3869473Z  ) from e 2024-12-17T23:28:40.3870067Z  return pull.user.login 2024-12-17T23:28:40.3870731Z  # In all other cases, return the original input username 2024-12-17T23:28:40.3871744Z  return username 2024-12-17T23:28:40.3872275Z  2024-12-17T23:28:40.3872666Z  2024-12-17T23:28:40.3873448Z def is_exception_branch(branch: str) -> bool: 2024-12-17T23:28:40.3874532Z  """ 2024-12-17T23:28:40.3875467Z  Branches that get opted out of experiments by default, until they're explicitly enabled. 2024-12-17T23:28:40.3876514Z  """ 2024-12-17T23:28:40.3877181Z  return branch.split("/")[0] in {"main", "nightly", "release", "landchecks"} 2024-12-17T23:28:40.3878002Z  2024-12-17T23:28:40.3878536Z  2024-12-17T23:28:40.3879035Z def load_yaml(yaml_text: str) -> Any: 2024-12-17T23:28:40.3879618Z  try: 2024-12-17T23:28:40.3880207Z  data = yaml.safe_load(yaml_text) 2024-12-17T23:28:40.3880833Z  return data 2024-12-17T23:28:40.3881357Z  except yaml.YAMLError: 2024-12-17T23:28:40.3882083Z  log.exception("Error loading YAML") 2024-12-17T23:28:40.3882719Z  raise 2024-12-17T23:28:40.3883207Z  2024-12-17T23:28:40.3883741Z  2024-12-17T23:28:40.3884479Z def extract_settings_user_opt_in_from_text(rollout_state: str) -> Tuple[str, str]: 2024-12-17T23:28:40.3885380Z  """ 2024-12-17T23:28:40.3886113Z  Extracts the text with settings, if any, and the opted in users from the rollout state. 2024-12-17T23:28:40.3886973Z  2024-12-17T23:28:40.3887659Z  If the issue body contains "---" then the text above that is the settings 2024-12-17T23:28:40.3888512Z  and the text below is the list of opted in users. 2024-12-17T23:28:40.3889185Z  2024-12-17T23:28:40.3889906Z  If it doesn't contain "---" then the settings are empty and the rest is the users. 2024-12-17T23:28:40.3890687Z  """ 2024-12-17T23:28:40.3891282Z  rollout_state_parts = rollout_state.split("---") 2024-12-17T23:28:40.3892046Z  if len(rollout_state_parts) >= 2: 2024-12-17T23:28:40.3892769Z  return rollout_state_parts[0], rollout_state_parts[1] 2024-12-17T23:28:40.3893482Z  else: 2024-12-17T23:28:40.3894195Z  return "", rollout_state 2024-12-17T23:28:40.3894842Z  2024-12-17T23:28:40.3895598Z  2024-12-17T23:28:40.3896219Z class UserOptins(Dict[str, List[str]]): 2024-12-17T23:28:40.3896886Z  """ 2024-12-17T23:28:40.3897497Z  Dictionary of users with a list of features they have opted into 2024-12-17T23:28:40.3898279Z  """ 2024-12-17T23:28:40.3898775Z  2024-12-17T23:28:40.3899171Z  2024-12-17T23:28:40.3899884Z def parse_user_opt_in_from_text(user_optin_text: str) -> UserOptins: 2024-12-17T23:28:40.3900658Z  """ 2024-12-17T23:28:40.3901457Z  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:40.3902454Z  2024-12-17T23:28:40.3903376Z  Users are GitHub usernames with the @ prefix. Each user is also a comma-separated list of features/experiments to enable. 2024-12-17T23:28:40.3904430Z  - Example line: "@User1,lf,split_build" 2024-12-17T23:28:40.3905282Z  - A "#" prefix indicates the user is opted out of all experiments 2024-12-17T23:28:40.3906028Z  2024-12-17T23:28:40.3906480Z  2024-12-17T23:28:40.3907046Z  """ 2024-12-17T23:28:40.3907631Z  optins = UserOptins() 2024-12-17T23:28:40.3908277Z  for user in user_optin_text.split("\n"): 2024-12-17T23:28:40.3908965Z  user = user.strip("\r\n\t -") 2024-12-17T23:28:40.3909647Z  if not user or not user.startswith("@"): 2024-12-17T23:28:40.3910332Z  # Not a valid user. Skip 2024-12-17T23:28:40.3911148Z  continue 2024-12-17T23:28:40.3911706Z  2024-12-17T23:28:40.3912160Z  if user: 2024-12-17T23:28:40.3912748Z  usr_name = user.split(",")[0].strip("@") 2024-12-17T23:28:40.3913588Z  optins[usr_name] = [exp.strip(" ") for exp in user.split(",")[1:]] 2024-12-17T23:28:40.3914318Z  2024-12-17T23:28:40.3914791Z  return optins 2024-12-17T23:28:40.3915354Z  2024-12-17T23:28:40.3915796Z  2024-12-17T23:28:40.3916407Z def is_valid_experiment_name(experiment_name: str) -> bool: 2024-12-17T23:28:40.3917156Z  """ 2024-12-17T23:28:40.3917749Z  Check if the experiment name is valid. 2024-12-17T23:28:40.3918394Z  A valid name: 2024-12-17T23:28:40.3919210Z  - Contains only alphanumeric characters and the special characters "_" & "-" 2024-12-17T23:28:40.3920233Z  - The special characters "_" & "-" shouldn't be the first or last characters 2024-12-17T23:28:40.3921123Z  - Cannot contain spaces 2024-12-17T23:28:40.3921687Z  """ 2024-12-17T23:28:40.3922155Z  2024-12-17T23:28:40.3922800Z  valid_char_regex = r"^[a-zA-Z0-9]([\w-]*[a-zA-Z0-9])?$" 2024-12-17T23:28:40.3923601Z  valid = bool(re.match(valid_char_regex, experiment_name)) 2024-12-17T23:28:40.3924314Z  2024-12-17T23:28:40.3924836Z  if valid: 2024-12-17T23:28:40.3925316Z  return True 2024-12-17T23:28:40.3925833Z  2024-12-17T23:28:40.3926353Z  log.error( 2024-12-17T23:28:40.3927847Z  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:40.3929418Z  ) 2024-12-17T23:28:40.3929976Z  return False 2024-12-17T23:28:40.3930450Z  2024-12-17T23:28:40.3930899Z  2024-12-17T23:28:40.3931571Z def parse_settings_from_text(settings_text: str) -> Settings: 2024-12-17T23:28:40.3932308Z  """ 2024-12-17T23:28:40.3933150Z  Parse the experiments from the issue body into a list of ExperimentSettings 2024-12-17T23:28:40.3934039Z  """ 2024-12-17T23:28:40.3934513Z  try: 2024-12-17T23:28:40.3934965Z  if settings_text: 2024-12-17T23:28:40.3936204Z  # Escape the backtick as well so that we can have the settings in a code block on the GH issue 2024-12-17T23:28:40.3937122Z  # for easy reading 2024-12-17T23:28:40.3938004Z  # Note: Using ascii for the backtick so that the cat step in _runner-determinator.yml doesn't choke on 2024-12-17T23:28:40.3939060Z  # the backtick character in shell commands. 2024-12-17T23:28:40.3939802Z  backtick = chr(96) # backtick character 2024-12-17T23:28:40.3940561Z  settings_text = settings_text.strip(f"\r\n\t{backtick} ") 2024-12-17T23:28:40.3941374Z  settings = load_yaml(settings_text) 2024-12-17T23:28:40.3942006Z  2024-12-17T23:28:40.3942697Z  # For now we just load experiments. We can expand this if/when we add more settings 2024-12-17T23:28:40.3943579Z  experiments = {} 2024-12-17T23:28:40.3944160Z  2024-12-17T23:28:40.3944802Z  for exp_name, exp_settings in settings.get(SETTING_EXPERIMENTS).items(): 2024-12-17T23:28:40.3945718Z  if not is_valid_experiment_name(exp_name): 2024-12-17T23:28:40.3946918Z  # 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:40.3948188Z  continue 2024-12-17T23:28:40.3948850Z  2024-12-17T23:28:40.3949288Z  valid_settings = {} 2024-12-17T23:28:40.3949907Z  for setting in exp_settings: 2024-12-17T23:28:40.3950702Z  if setting not in Experiment._fields: 2024-12-17T23:28:40.3951333Z  log.warning( 2024-12-17T23:28:40.3952133Z  f"Unexpected setting in experiment: {setting} = {exp_settings[setting]}" 2024-12-17T23:28:40.3953028Z  ) 2024-12-17T23:28:40.3953539Z  else: 2024-12-17T23:28:40.3954386Z  valid_settings[setting] = exp_settings[setting] 2024-12-17T23:28:40.3955733Z  2024-12-17T23:28:40.3956714Z  experiments[exp_name] = Experiment(**valid_settings) 2024-12-17T23:28:40.3957915Z  return Settings(experiments) 2024-12-17T23:28:40.3958679Z  2024-12-17T23:28:40.3959140Z  except Exception: 2024-12-17T23:28:40.3959736Z  log.exception("Failed to parse settings") 2024-12-17T23:28:40.3960513Z  2024-12-17T23:28:40.3960988Z  return Settings() 2024-12-17T23:28:40.3961476Z  2024-12-17T23:28:40.3961998Z  2024-12-17T23:28:40.3962573Z def parse_settings(rollout_state: str) -> Settings: 2024-12-17T23:28:40.3963205Z  """ 2024-12-17T23:28:40.3963848Z  Parse settings, if any, from the rollout state. 2024-12-17T23:28:40.3964519Z  2024-12-17T23:28:40.3965106Z  If the issue body contains "---" then the text above that is the settings 2024-12-17T23:28:40.3966045Z  and the text below is the list of opted in users. 2024-12-17T23:28:40.3966715Z  2024-12-17T23:28:40.3967354Z  If it doesn't contain "---" then the settings are empty and the default values are used. 2024-12-17T23:28:40.3968268Z  """ 2024-12-17T23:28:40.3968952Z  settings_text, _ = extract_settings_user_opt_in_from_text(rollout_state) 2024-12-17T23:28:40.3969864Z  return parse_settings_from_text(settings_text) 2024-12-17T23:28:40.3970493Z  2024-12-17T23:28:40.3971126Z  2024-12-17T23:28:40.3971755Z def parse_users(rollout_state: str) -> UserOptins: 2024-12-17T23:28:40.3972426Z  """ 2024-12-17T23:28:40.3972944Z  Parse users from the rollout state. 2024-12-17T23:28:40.3973603Z  2024-12-17T23:28:40.3974043Z  """ 2024-12-17T23:28:40.3974694Z  _, users_text = extract_settings_user_opt_in_from_text(rollout_state) 2024-12-17T23:28:40.3976293Z  return parse_user_opt_in_from_text(users_text) 2024-12-17T23:28:40.3976962Z  2024-12-17T23:28:40.3977400Z  2024-12-17T23:28:40.3978186Z def is_user_opted_in(user: str, user_optins: UserOptins, experiment_name: str) -> bool: 2024-12-17T23:28:40.3979027Z  """ 2024-12-17T23:28:40.3979568Z  Check if a user is opted into an experiment 2024-12-17T23:28:40.3980273Z  """ 2024-12-17T23:28:40.3980840Z  return experiment_name in user_optins.get(user, []) 2024-12-17T23:28:40.3981513Z  2024-12-17T23:28:40.3982009Z  2024-12-17T23:28:40.3982706Z def is_user_opted_out(user: str, user_optins: UserOptins, experiment_name: str) -> bool: 2024-12-17T23:28:40.3983596Z  """ 2024-12-17T23:28:40.3984255Z  Check if a user explicitly opted out of an experiment 2024-12-17T23:28:40.3984950Z  """ 2024-12-17T23:28:40.3985542Z  # if the experiment is prefixed with a "-", then it's an opt-out 2024-12-17T23:28:40.3986404Z  experiment_optout = "-" + experiment_name 2024-12-17T23:28:40.3987177Z  if experiment_optout not in user_optins.get(user, []): 2024-12-17T23:28:40.3988058Z  return False 2024-12-17T23:28:40.3988630Z  2024-12-17T23:28:40.3989211Z  if is_user_opted_in(user, user_optins, experiment_name): 2024-12-17T23:28:40.3989893Z  log.warning( 2024-12-17T23:28:40.3990866Z  f"User {user} is opted into experiment {experiment_name}, but also opted out of it. Defaulting to opting out" 2024-12-17T23:28:40.3991852Z  ) 2024-12-17T23:28:40.3992312Z  2024-12-17T23:28:40.3992802Z  return True 2024-12-17T23:28:40.3993345Z  2024-12-17T23:28:40.3993746Z  2024-12-17T23:28:40.3994254Z def get_runner_prefix( 2024-12-17T23:28:40.3994849Z  rollout_state: str, 2024-12-17T23:28:40.3995415Z  workflow_requestors: Iterable[str], 2024-12-17T23:28:40.3996084Z  branch: str, 2024-12-17T23:28:40.3996804Z  eligible_experiments: FrozenSet[str] = frozenset(), 2024-12-17T23:28:40.3997566Z  is_canary: bool = False, 2024-12-17T23:28:40.3998171Z ) -> str: 2024-12-17T23:28:40.3998755Z  settings = parse_settings(rollout_state) 2024-12-17T23:28:40.3999456Z  user_optins = parse_users(rollout_state) 2024-12-17T23:28:40.4000097Z  2024-12-17T23:28:40.4000591Z  fleet_prefix = "" 2024-12-17T23:28:40.4001145Z  prefixes = [] 2024-12-17T23:28:40.4001921Z  for experiment_name, experiment_settings in settings.experiments.items(): 2024-12-17T23:28:40.4003002Z  if not experiment_settings.all_branches and is_exception_branch(branch): 2024-12-17T23:28:40.4003806Z  log.info( 2024-12-17T23:28:40.4004635Z  f"Branch {branch} is an exception branch. Not enabling experiment {experiment_name}." 2024-12-17T23:28:40.4005488Z  ) 2024-12-17T23:28:40.4006021Z  continue 2024-12-17T23:28:40.4006643Z  2024-12-17T23:28:40.4007096Z  if eligible_experiments: 2024-12-17T23:28:40.4007790Z  if experiment_name not in eligible_experiments: 2024-12-17T23:28:40.4008610Z  exp_list = ", ".join(eligible_experiments) 2024-12-17T23:28:40.4009373Z  log.info( 2024-12-17T23:28:40.4010287Z  f"Skipping experiment '{experiment_name}', as it is not in the eligible_experiments list: {exp_list}" 2024-12-17T23:28:40.4011278Z  ) 2024-12-17T23:28:40.4011769Z  continue 2024-12-17T23:28:40.4012380Z  elif not experiment_settings.default: 2024-12-17T23:28:40.4013087Z  log.info( 2024-12-17T23:28:40.4013855Z  f"Skipping experiment '{experiment_name}', as it is not a default experiment" 2024-12-17T23:28:40.4014656Z  ) 2024-12-17T23:28:40.4015449Z  continue 2024-12-17T23:28:40.4016018Z  2024-12-17T23:28:40.4016541Z  # Is any workflow_requestor opted out to this experiment? 2024-12-17T23:28:40.4017346Z  opted_out_users = [ 2024-12-17T23:28:40.4018054Z  requestor 2024-12-17T23:28:40.4018622Z  for requestor in workflow_requestors 2024-12-17T23:28:40.4019503Z  if is_user_opted_out(requestor, user_optins, experiment_name) 2024-12-17T23:28:40.4020234Z  ] 2024-12-17T23:28:40.4020648Z  2024-12-17T23:28:40.4021204Z  if opted_out_users: 2024-12-17T23:28:40.4021785Z  log.info( 2024-12-17T23:28:40.4022484Z  f"{', '.join(opted_out_users)} have opted out of experiment {experiment_name}." 2024-12-17T23:28:40.4023387Z  ) 2024-12-17T23:28:40.4023890Z  continue 2024-12-17T23:28:40.4024548Z  2024-12-17T23:28:40.4025210Z  # Is any workflow_requestor opted in to this experiment? 2024-12-17T23:28:40.4025921Z  opted_in_users = [ 2024-12-17T23:28:40.4026435Z  requestor 2024-12-17T23:28:40.4027131Z  for requestor in workflow_requestors 2024-12-17T23:28:40.4027904Z  if is_user_opted_in(requestor, user_optins, experiment_name) 2024-12-17T23:28:40.4028680Z  ] 2024-12-17T23:28:40.4029135Z  2024-12-17T23:28:40.4029586Z  enabled = False 2024-12-17T23:28:40.4030208Z  if opted_in_users: 2024-12-17T23:28:40.4030775Z  log.info( 2024-12-17T23:28:40.4031507Z  f"{', '.join(opted_in_users)} have opted into experiment {experiment_name}." 2024-12-17T23:28:40.4032336Z  ) 2024-12-17T23:28:40.4032819Z  enabled = True 2024-12-17T23:28:40.4033373Z  2024-12-17T23:28:40.4033941Z  elif experiment_settings.rollout_perc: 2024-12-17T23:28:40.4034841Z  # If no user is opted in, then we randomly enable the experiment based on the rollout percentage 2024-12-17T23:28:40.4035878Z  if random.uniform(0, 100) <= experiment_settings.rollout_perc: 2024-12-17T23:28:40.4036668Z  log.info( 2024-12-17T23:28:40.4037652Z  f"Based on rollout percentage of {experiment_settings.rollout_perc}%, enabling experiment {experiment_name}." 2024-12-17T23:28:40.4038617Z  ) 2024-12-17T23:28:40.4039208Z  enabled = True 2024-12-17T23:28:40.4039794Z  2024-12-17T23:28:40.4040224Z  if enabled: 2024-12-17T23:28:40.4040921Z  label = experiment_name 2024-12-17T23:28:40.4041613Z  if experiment_name == LF_FLEET_EXPERIMENT: 2024-12-17T23:28:40.4042523Z  # We give some special treatment to the "lf" experiment since determines the fleet we use 2024-12-17T23:28:40.4043527Z  # - If it's enabled, then we always list it's prefix first 2024-12-17T23:28:40.4044564Z  # - If we're in the canary branch, then we append ".c" to the lf prefix 2024-12-17T23:28:40.4045331Z  if is_canary: 2024-12-17T23:28:40.4045974Z  label += CANARY_FLEET_SUFFIX 2024-12-17T23:28:40.4046657Z  fleet_prefix = label 2024-12-17T23:28:40.4047260Z  else: 2024-12-17T23:28:40.4047834Z  prefixes.append(label) 2024-12-17T23:28:40.4048472Z  2024-12-17T23:28:40.4048923Z  if len(prefixes) > 1: 2024-12-17T23:28:40.4049494Z  log.error( 2024-12-17T23:28:40.4050679Z  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:40.4051857Z  ) 2024-12-17T23:28:40.4052437Z  prefixes = prefixes[:1] 2024-12-17T23:28:40.4052986Z  2024-12-17T23:28:40.4053452Z  # Fleet always comes first 2024-12-17T23:28:40.4054121Z  if fleet_prefix: 2024-12-17T23:28:40.4054673Z  prefixes.insert(0, fleet_prefix) 2024-12-17T23:28:40.4055502Z  2024-12-17T23:28:40.4056187Z  return ".".join(prefixes) + "." if prefixes else "" 2024-12-17T23:28:40.4056825Z  2024-12-17T23:28:40.4057261Z  2024-12-17T23:28:40.4058070Z def get_rollout_state_from_issue(github_token: str, repo: str, issue_num: int) -> str: 2024-12-17T23:28:40.4058894Z  """ 2024-12-17T23:28:40.4059602Z  Gets the first comment of the issue, which contains the desired rollout state. 2024-12-17T23:28:40.4060458Z  2024-12-17T23:28:40.4061282Z  The default issue we use - https://github.com/pytorch/test-infra/issues/5132 2024-12-17T23:28:40.4062099Z  """ 2024-12-17T23:28:40.4062679Z  gh = get_gh_client(github_token) 2024-12-17T23:28:40.4063342Z  issue = get_issue(gh, repo, issue_num) 2024-12-17T23:28:40.4064138Z  return str(issue.get_comments()[0].body.strip("\n\t ")) 2024-12-17T23:28:40.4064922Z  2024-12-17T23:28:40.4065332Z  2024-12-17T23:28:40.4066043Z def download_json(url: str, headers: Dict[str, str], num_retries: int = 3) -> Any: 2024-12-17T23:28:40.4066975Z  for _ in range(num_retries): 2024-12-17T23:28:40.4067608Z  try: 2024-12-17T23:28:40.4068124Z  req = Request(url=url, headers=headers) 2024-12-17T23:28:40.4068955Z  content = urlopen(req, timeout=5).read().decode("utf-8") 2024-12-17T23:28:40.4069717Z  return json.loads(content) 2024-12-17T23:28:40.4070316Z  except Exception as e: 2024-12-17T23:28:40.4071050Z  log.warning(f"Could not download {url}: {e}") 2024-12-17T23:28:40.4071729Z  2024-12-17T23:28:40.4072373Z  log.warning(f"All {num_retries} retries exhausted, downloading {url} failed") 2024-12-17T23:28:40.4073247Z  return {} 2024-12-17T23:28:40.4073764Z  2024-12-17T23:28:40.4074158Z  2024-12-17T23:28:40.4074697Z @lru_cache(maxsize=None) 2024-12-17T23:28:40.4075536Z def get_pr_info(github_repo: str, github_token: str, pr_number: int) -> Dict[str, Any]: 2024-12-17T23:28:40.4076346Z  """ 2024-12-17T23:28:40.4076944Z  Dynamically get PR information 2024-12-17T23:28:40.4077539Z  """ 2024-12-17T23:28:40.4078138Z  github_api = f"https://api.github.com/repos/{github_repo}" 2024-12-17T23:28:40.4078919Z  headers = { 2024-12-17T23:28:40.4079530Z  "Accept": "application/vnd.github.v3+json", 2024-12-17T23:28:40.4080229Z  "Authorization": f"token {github_token}", 2024-12-17T23:28:40.4080922Z  } 2024-12-17T23:28:40.4081472Z  json_response: Dict[str, Any] = download_json( 2024-12-17T23:28:40.4082339Z  url=f"{github_api}/issues/{pr_number}", 2024-12-17T23:28:40.4083033Z  headers=headers, 2024-12-17T23:28:40.4083626Z  ) 2024-12-17T23:28:40.4084077Z  2024-12-17T23:28:40.4084574Z  if not json_response: 2024-12-17T23:28:40.4085279Z  log.warning(f"Failed to get the labels for #{pr_number}") 2024-12-17T23:28:40.4085996Z  return {} 2024-12-17T23:28:40.4086558Z  2024-12-17T23:28:40.4087031Z  return json_response 2024-12-17T23:28:40.4087571Z  2024-12-17T23:28:40.4088039Z  2024-12-17T23:28:40.4088738Z def get_labels(github_repo: str, github_token: str, pr_number: int) -> Set[str]: 2024-12-17T23:28:40.4089541Z  """ 2024-12-17T23:28:40.4090225Z  Dynamically get the latest list of labels from the pull request 2024-12-17T23:28:40.4090976Z  """ 2024-12-17T23:28:40.4091562Z  pr_info = get_pr_info(github_repo, github_token, pr_number) 2024-12-17T23:28:40.4092353Z  return { 2024-12-17T23:28:40.4093032Z  label.get("name") for label in pr_info.get("labels", []) if label.get("name") 2024-12-17T23:28:40.4093792Z  } 2024-12-17T23:28:40.4094337Z  2024-12-17T23:28:40.4094753Z  2024-12-17T23:28:40.4095657Z def main() -> None: 2024-12-17T23:28:40.4096391Z  args = parse_args() 2024-12-17T23:28:40.4096903Z  2024-12-17T23:28:40.4097408Z  runner_label_prefix = DEFAULT_LABEL_PREFIX 2024-12-17T23:28:40.4098152Z  2024-12-17T23:28:40.4098589Z  # Check if the PR is opt-out 2024-12-17T23:28:40.4099362Z  if args.pr_number: 2024-12-17T23:28:40.4100257Z  labels = get_labels(args.github_repo, args.github_token, int(args.pr_number)) 2024-12-17T23:28:40.4101061Z  if OPT_OUT_LABEL in labels: 2024-12-17T23:28:40.4101644Z  log.info( 2024-12-17T23:28:40.4102569Z  f"Opt-out runner determinator because #{args.pr_number} has {OPT_OUT_LABEL} label" 2024-12-17T23:28:40.4103381Z  ) 2024-12-17T23:28:40.4104044Z  set_github_output(GH_OUTPUT_KEY_LABEL_TYPE, runner_label_prefix) 2024-12-17T23:28:40.4104899Z  sys.exit() 2024-12-17T23:28:40.4105439Z  2024-12-17T23:28:40.4105851Z  try: 2024-12-17T23:28:40.4106484Z  rollout_state = get_rollout_state_from_issue( 2024-12-17T23:28:40.4107300Z  args.github_token, args.github_issue_repo, args.github_issue 2024-12-17T23:28:40.4108002Z  ) 2024-12-17T23:28:40.4108554Z  2024-12-17T23:28:40.4109046Z  username = get_potential_pr_author( 2024-12-17T23:28:40.4109644Z  args.github_token, 2024-12-17T23:28:40.4110344Z  args.github_repo, 2024-12-17T23:28:40.4110953Z  args.github_actor, 2024-12-17T23:28:40.4111505Z  args.github_ref_type, 2024-12-17T23:28:40.4112192Z  args.github_branch, 2024-12-17T23:28:40.4112775Z  ) 2024-12-17T23:28:40.4113193Z  2024-12-17T23:28:40.4113849Z  is_canary = args.github_repo == "pytorch/pytorch-canary" 2024-12-17T23:28:40.4114564Z  2024-12-17T23:28:40.4115021Z  runner_label_prefix = get_runner_prefix( 2024-12-17T23:28:40.4115746Z  rollout_state, 2024-12-17T23:28:40.4116376Z  (args.github_issue_owner, username), 2024-12-17T23:28:40.4116987Z  args.github_branch, 2024-12-17T23:28:40.4117686Z  args.eligible_experiments, 2024-12-17T23:28:40.4118313Z  is_canary, 2024-12-17T23:28:40.4118960Z  ) 2024-12-17T23:28:40.4119472Z  2024-12-17T23:28:40.4120006Z  except Exception as e: 2024-12-17T23:28:40.4120825Z  log.error( 2024-12-17T23:28:40.4121656Z  f"Failed to get issue. Defaulting to Meta runners and no experiments. Exception: {e}" 2024-12-17T23:28:40.4122488Z  ) 2024-12-17T23:28:40.4123011Z  2024-12-17T23:28:40.4123637Z  set_github_output(GH_OUTPUT_KEY_LABEL_TYPE, runner_label_prefix) 2024-12-17T23:28:40.4124553Z  2024-12-17T23:28:40.4125348Z  2024-12-17T23:28:40.4126079Z if __name__ == "__main__": 2024-12-17T23:28:40.4126803Z  main() 2024-12-17T23:28:40.4127382Z  2024-12-17T23:28:40.4127814Z EOF 2024-12-17T23:28:40.4128260Z  2024-12-17T23:28:40.4128790Z cat runner_determinator.py 2024-12-17T23:28:40.4901511Z shell: /usr/bin/bash -e {0} 2024-12-17T23:28:40.4902474Z env: 2024-12-17T23:28:40.4903205Z GITHUB_TOKEN: *** 2024-12-17T23:28:40.4903761Z ISSUE_NUMBER: 5132 2024-12-17T23:28:40.4904315Z TRIGGERING_ACTOR: malfet 2024-12-17T23:28:40.4904875Z ISSUE_OWNER: 2024-12-17T23:28:40.4905398Z CHECK_EXPERIMENTS: 2024-12-17T23:28:40.4905968Z PR_NUMBER: 2024-12-17T23:28:40.4906461Z ##[endgroup] 2024-12-17T23:28:40.5134911Z # flake8: noqa: G004 2024-12-17T23:28:40.5135615Z 2024-12-17T23:28:40.5136099Z # Note: Copies of this script in runner_determinator.py and _runner-determinator.yml 2024-12-17T23:28:40.5137206Z # must be kept in sync. You can do it easily by running the following command: 2024-12-17T23:28:40.5138082Z # python .github/scripts/update_runner_determinator.py 2024-12-17T23:28:40.5138583Z 2024-12-17T23:28:40.5138768Z """ 2024-12-17T23:28:40.5140121Z This runner determinator is used to determine which set of runners to run a 2024-12-17T23:28:40.5141109Z GitHub job on. It uses the first comment of a GitHub issue (by default 2024-12-17T23:28:40.5142046Z https://github.com/pytorch/test-infra/issues/5132) to define the configuration 2024-12-17T23:28:40.5142976Z of which runners should be used to run which job. 2024-12-17T23:28:40.5143437Z 2024-12-17T23:28:40.5143881Z The configuration has two parts, the settings and a list of opted-in users, 2024-12-17T23:28:40.5144807Z separated by a line containing "---". If the line is not present, the 2024-12-17T23:28:40.5145770Z settings are considered to be empty with only the second part, the user 2024-12-17T23:28:40.5146544Z list, defined. 2024-12-17T23:28:40.5146807Z 2024-12-17T23:28:40.5147179Z The first part is a YAML block that defines the rollout settings. This can be 2024-12-17T23:28:40.5148183Z used to define any settings that are needed to determine which runners to use. 2024-12-17T23:28:40.5149084Z It's fields are defined by the RolloutSettings class below. 2024-12-17T23:28:40.5149561Z 2024-12-17T23:28:40.5149990Z The second part is a list of users who are explicitly opted in to the LF fleet. 2024-12-17T23:28:40.5150921Z The user list is also a comma separated list of additional features or 2024-12-17T23:28:40.5151745Z experiments which the user could be opted in to. 2024-12-17T23:28:40.5152165Z 2024-12-17T23:28:40.5152417Z The user list has the following rules: 2024-12-17T23:28:40.5152757Z 2024-12-17T23:28:40.5153144Z - Users are GitHub usernames, which must start with the @ prefix 2024-12-17T23:28:40.5154085Z - Each user is also a comma-separated list of features/experiments to enable 2024-12-17T23:28:40.5154899Z - A "#" prefix opts the user out of all experiments 2024-12-17T23:28:40.5155287Z 2024-12-17T23:28:40.5155544Z Example config: 2024-12-17T23:28:40.5156111Z # A list of experiments that can be opted into. 2024-12-17T23:28:40.5156843Z # This defines the behavior they'll induce when opted into. 2024-12-17T23:28:40.5157647Z # Expected syntax is: 2024-12-17T23:28:40.5158388Z # [experiment_name]: # Name of the experiment. Also used for the label prefix. 2024-12-17T23:28:40.5159422Z # rollout_perc: [int] # % of workflows to run with this experiment when users are not opted in. 2024-12-17T23:28:40.5160013Z 2024-12-17T23:28:40.5160507Z experiments: 2024-12-17T23:28:40.5160966Z lf: 2024-12-17T23:28:40.5161419Z rollout_percent: 25 2024-12-17T23:28:40.5162048Z all_branches: false 2024-12-17T23:28:40.5162544Z default: true 2024-12-17T23:28:40.5163026Z --- 2024-12-17T23:28:40.5163232Z 2024-12-17T23:28:40.5163546Z # Opt-ins: 2024-12-17T23:28:40.5164159Z # Users can opt into the LF fleet by adding their GitHub username to this list 2024-12-17T23:28:40.5165073Z # and specifying experiments to enable in a comma-separated list. 2024-12-17T23:28:40.5165993Z # To always opt out of an experiment, prefix it with a "-". 2024-12-17T23:28:40.5166698Z # Experiments should be from the above list. 2024-12-17T23:28:40.5167123Z 2024-12-17T23:28:40.5167341Z @User1,-lf,split_build 2024-12-17T23:28:40.5167924Z @User2,lf 2024-12-17T23:28:40.5168360Z @User3,split_build 2024-12-17T23:28:40.5168861Z """ 2024-12-17T23:28:40.5169059Z 2024-12-17T23:28:40.5169371Z import json 2024-12-17T23:28:40.5169786Z import logging 2024-12-17T23:28:40.5170260Z import os 2024-12-17T23:28:40.5170928Z import random 2024-12-17T23:28:40.5171366Z import re 2024-12-17T23:28:40.5171823Z import sys 2024-12-17T23:28:40.5172363Z from argparse import ArgumentParser 2024-12-17T23:28:40.5172940Z from functools import lru_cache 2024-12-17T23:28:40.5173516Z from logging import LogRecord 2024-12-17T23:28:40.5174323Z from typing import Any, Dict, FrozenSet, Iterable, List, NamedTuple, Set, Tuple 2024-12-17T23:28:40.5175118Z from urllib.request import Request, urlopen 2024-12-17T23:28:40.5175883Z 2024-12-17T23:28:40.5176079Z import yaml 2024-12-17T23:28:40.5176923Z from github import Auth, Github 2024-12-17T23:28:40.5177476Z from github.Issue import Issue 2024-12-17T23:28:40.5177829Z 2024-12-17T23:28:40.5177835Z 2024-12-17T23:28:40.5178070Z DEFAULT_LABEL_PREFIX = "" # use meta runners 2024-12-17T23:28:40.5178890Z WORKFLOW_LABEL_LF = "lf." # use runners from the linux foundation 2024-12-17T23:28:40.5179784Z WORKFLOW_LABEL_LF_CANARY = "lf.c." # use canary runners from the linux foundation 2024-12-17T23:28:40.5180368Z 2024-12-17T23:28:40.5180614Z GITHUB_OUTPUT = os.getenv("GITHUB_OUTPUT", "") 2024-12-17T23:28:40.5181351Z GH_OUTPUT_KEY_AMI = "runner-ami" 2024-12-17T23:28:40.5181926Z GH_OUTPUT_KEY_LABEL_TYPE = "label-type" 2024-12-17T23:28:40.5182502Z OPT_OUT_LABEL = "no-runner-experiments" 2024-12-17T23:28:40.5182962Z 2024-12-17T23:28:40.5183209Z SETTING_EXPERIMENTS = "experiments" 2024-12-17T23:28:40.5183557Z 2024-12-17T23:28:40.5183795Z LF_FLEET_EXPERIMENT = "lf" 2024-12-17T23:28:40.5184301Z CANARY_FLEET_SUFFIX = ".c" 2024-12-17T23:28:40.5184687Z 2024-12-17T23:28:40.5184702Z 2024-12-17T23:28:40.5184953Z class Experiment(NamedTuple): 2024-12-17T23:28:40.5185499Z rollout_perc: float = ( 2024-12-17T23:28:40.5186162Z 0 # Percentage of workflows to experiment on when user is not opted-in. 2024-12-17T23:28:40.5186987Z ) 2024-12-17T23:28:40.5187431Z all_branches: bool = ( 2024-12-17T23:28:40.5188083Z False # If True, the experiment is also enabled on the exception branches 2024-12-17T23:28:40.5188911Z ) 2024-12-17T23:28:40.5189343Z default: bool = ( 2024-12-17T23:28:40.5189931Z True # If True, the experiment is enabled by default for all queries 2024-12-17T23:28:40.5190710Z ) 2024-12-17T23:28:40.5190929Z 2024-12-17T23:28:40.5191163Z # Add more fields as needed 2024-12-17T23:28:40.5191476Z 2024-12-17T23:28:40.5191482Z 2024-12-17T23:28:40.5191728Z class Settings(NamedTuple): 2024-12-17T23:28:40.5192288Z """ 2024-12-17T23:28:40.5192801Z Settings for the experiments that can be opted into. 2024-12-17T23:28:40.5193440Z """ 2024-12-17T23:28:40.5193718Z 2024-12-17T23:28:40.5193965Z experiments: Dict[str, Experiment] = {} 2024-12-17T23:28:40.5194374Z 2024-12-17T23:28:40.5194379Z 2024-12-17T23:28:40.5194607Z class ColorFormatter(logging.Formatter): 2024-12-17T23:28:40.5195290Z """Color codes the log messages based on the log level""" 2024-12-17T23:28:40.5195957Z 2024-12-17T23:28:40.5196178Z COLORS = { 2024-12-17T23:28:40.5196672Z "WARNING": "\033[33m", # Yellow 2024-12-17T23:28:40.5197270Z "ERROR": "\033[31m", # Red 2024-12-17T23:28:40.5197885Z "CRITICAL": "\033[31m", # Red 2024-12-17T23:28:40.5198465Z "INFO": "\033[0m", # Reset 2024-12-17T23:28:40.5199001Z "DEBUG": "\033[0m", # Reset 2024-12-17T23:28:40.5199584Z } 2024-12-17T23:28:40.5199855Z 2024-12-17T23:28:40.5200088Z def format(self, record: LogRecord) -> str: 2024-12-17T23:28:40.5200870Z log_color = self.COLORS.get(record.levelname, "\033[0m") # Default to reset 2024-12-17T23:28:40.5201754Z record.msg = f"{log_color}{record.msg}\033[0m" 2024-12-17T23:28:40.5202409Z return super().format(record) 2024-12-17T23:28:40.5202759Z 2024-12-17T23:28:40.5202801Z 2024-12-17T23:28:40.5203008Z handler = logging.StreamHandler() 2024-12-17T23:28:40.5203879Z handler.setFormatter(ColorFormatter(fmt="%(levelname)-8s: %(message)s")) 2024-12-17T23:28:40.5204445Z 2024-12-17T23:28:40.5204707Z log = logging.getLogger(os.path.basename(__file__)) 2024-12-17T23:28:40.5205352Z log.addHandler(handler) 2024-12-17T23:28:40.5205971Z log.setLevel(logging.INFO) 2024-12-17T23:28:40.5206271Z 2024-12-17T23:28:40.5206277Z 2024-12-17T23:28:40.5206540Z def set_github_output(key: str, value: str) -> None: 2024-12-17T23:28:40.5207152Z """ 2024-12-17T23:28:40.5207823Z Defines outputs of the github action that invokes this script 2024-12-17T23:28:40.5208473Z """ 2024-12-17T23:28:40.5208894Z if not GITHUB_OUTPUT: 2024-12-17T23:28:40.5210094Z # See https://github.blog/changelog/2022-10-11-github-actions-deprecating-save-state-and-set-output-commands/ for deprecation notice 2024-12-17T23:28:40.5211359Z log.warning( 2024-12-17T23:28:40.5212263Z "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:40.5213326Z ) 2024-12-17T23:28:40.5223552Z print(f"::set-output name={key}::{value}") 2024-12-17T23:28:40.5224234Z return 2024-12-17T23:28:40.5224632Z 2024-12-17T23:28:40.5224876Z with open(GITHUB_OUTPUT, "a") as f: 2024-12-17T23:28:40.5225517Z log.info(f"Setting output: {key}='{value}'") 2024-12-17T23:28:40.5226112Z f.write(f"{key}={value}\n") 2024-12-17T23:28:40.5226579Z 2024-12-17T23:28:40.5226585Z 2024-12-17T23:28:40.5226925Z def _str_comma_separated_to_set(value: str) -> FrozenSet[str]: 2024-12-17T23:28:40.5227631Z return frozenset( 2024-12-17T23:28:40.5228251Z filter(lambda itm: itm != "", map(str.strip, value.strip(" \n\t").split(","))) 2024-12-17T23:28:40.5229114Z ) 2024-12-17T23:28:40.5229324Z 2024-12-17T23:28:40.5229331Z 2024-12-17T23:28:40.5229575Z def parse_args() -> Any: 2024-12-17T23:28:40.5230136Z parser = ArgumentParser("Get dynamic rollout settings") 2024-12-17T23:28:40.5231149Z parser.add_argument("--github-token", type=str, required=True, help="GitHub token") 2024-12-17T23:28:40.5231971Z parser.add_argument( 2024-12-17T23:28:40.5232444Z "--github-issue-repo", 2024-12-17T23:28:40.5233083Z type=str, 2024-12-17T23:28:40.5233542Z required=False, 2024-12-17T23:28:40.5234009Z default="pytorch/test-infra", 2024-12-17T23:28:40.5234711Z help="GitHub repo to get the issue", 2024-12-17T23:28:40.5235289Z ) 2024-12-17T23:28:40.5235683Z parser.add_argument( 2024-12-17T23:28:40.5236288Z "--github-repo", 2024-12-17T23:28:40.5236785Z type=str, 2024-12-17T23:28:40.5237216Z required=True, 2024-12-17T23:28:40.5237855Z help="GitHub repo where CI is running", 2024-12-17T23:28:40.5238446Z ) 2024-12-17T23:28:40.5238843Z parser.add_argument( 2024-12-17T23:28:40.5239589Z "--github-issue", type=int, required=True, help="GitHub issue number" 2024-12-17T23:28:40.5240298Z ) 2024-12-17T23:28:40.5240695Z parser.add_argument( 2024-12-17T23:28:40.5241648Z "--github-actor", type=str, required=True, help="GitHub triggering_actor" 2024-12-17T23:28:40.5242426Z ) 2024-12-17T23:28:40.5242819Z parser.add_argument( 2024-12-17T23:28:40.5243621Z "--github-issue-owner", type=str, required=True, help="GitHub issue owner" 2024-12-17T23:28:40.5244390Z ) 2024-12-17T23:28:40.5244780Z parser.add_argument( 2024-12-17T23:28:40.5245567Z "--github-branch", type=str, required=True, help="Current GitHub branch or tag" 2024-12-17T23:28:40.5246347Z ) 2024-12-17T23:28:40.5246738Z parser.add_argument( 2024-12-17T23:28:40.5247346Z "--github-ref-type", 2024-12-17T23:28:40.5247886Z type=str, 2024-12-17T23:28:40.5248304Z required=True, 2024-12-17T23:28:40.5248953Z help="Current GitHub ref type, branch or tag", 2024-12-17T23:28:40.5249567Z ) 2024-12-17T23:28:40.5249957Z parser.add_argument( 2024-12-17T23:28:40.5250599Z "--eligible-experiments", 2024-12-17T23:28:40.5251181Z type=_str_comma_separated_to_set, 2024-12-17T23:28:40.5251722Z required=False, 2024-12-17T23:28:40.5252314Z default="", 2024-12-17T23:28:40.5253194Z help="comma separated list of experiments to check, if omitted all experiments marked with default=True are checked", 2024-12-17T23:28:40.5254124Z ) 2024-12-17T23:28:40.5254669Z parser.add_argument( 2024-12-17T23:28:40.5255179Z "--pr-number", 2024-12-17T23:28:40.5256041Z type=str, 2024-12-17T23:28:40.5256626Z required=False, 2024-12-17T23:28:40.5257113Z default="", 2024-12-17T23:28:40.5257592Z help="the optional PR number where this is run", 2024-12-17T23:28:40.5258317Z ) 2024-12-17T23:28:40.5258737Z 2024-12-17T23:28:40.5258985Z return parser.parse_args() 2024-12-17T23:28:40.5259323Z 2024-12-17T23:28:40.5259330Z 2024-12-17T23:28:40.5259670Z def get_gh_client(github_token: str) -> Github: 2024-12-17T23:28:40.5260285Z auth = Auth.Token(github_token) 2024-12-17T23:28:40.5260857Z return Github(auth=auth) 2024-12-17T23:28:40.5261190Z 2024-12-17T23:28:40.5261196Z 2024-12-17T23:28:40.5261594Z def get_issue(gh: Github, repo: str, issue_num: int) -> Issue: 2024-12-17T23:28:40.5262291Z repo = gh.get_repo(repo) 2024-12-17T23:28:40.5262874Z return repo.get_issue(number=issue_num) 2024-12-17T23:28:40.5263249Z 2024-12-17T23:28:40.5263255Z 2024-12-17T23:28:40.5263550Z def get_potential_pr_author( 2024-12-17T23:28:40.5264222Z github_token: str, repo: str, username: str, ref_type: str, ref_name: str 2024-12-17T23:28:40.5264969Z ) -> str: 2024-12-17T23:28:40.5265612Z # If the trigger was a new tag added by a bot, this is a ciflow case 2024-12-17T23:28:40.5266454Z # Fetch the actual username from the original PR. The PR number is 2024-12-17T23:28:40.5267269Z # embedded in the tag name: ciflow// 2024-12-17T23:28:40.5267692Z 2024-12-17T23:28:40.5267978Z gh = get_gh_client(github_token) 2024-12-17T23:28:40.5268344Z 2024-12-17T23:28:40.5268663Z if username == "pytorch-bot[bot]" and ref_type == "tag": 2024-12-17T23:28:40.5269328Z split_tag = ref_name.split("/") 2024-12-17T23:28:40.5269948Z if ( 2024-12-17T23:28:40.5270444Z len(split_tag) == 3 2024-12-17T23:28:40.5270950Z and split_tag[0] == "ciflow" 2024-12-17T23:28:40.5271584Z and split_tag[2].isnumeric() 2024-12-17T23:28:40.5272176Z ): 2024-12-17T23:28:40.5272587Z pr_number = split_tag[2] 2024-12-17T23:28:40.5273184Z try: 2024-12-17T23:28:40.5273710Z repository = gh.get_repo(repo) 2024-12-17T23:28:40.5274354Z pull = repository.get_pull(number=int(pr_number)) 2024-12-17T23:28:40.5275058Z except Exception as e: 2024-12-17T23:28:40.5275667Z raise Exception( # noqa: TRY002 2024-12-17T23:28:40.5276351Z f"issue with pull request {pr_number} from repo {repository}" 2024-12-17T23:28:40.5277400Z ) from e 2024-12-17T23:28:40.5277965Z return pull.user.login 2024-12-17T23:28:40.5278751Z # In all other cases, return the original input username 2024-12-17T23:28:40.5279477Z return username 2024-12-17T23:28:40.5279754Z 2024-12-17T23:28:40.5279760Z 2024-12-17T23:28:40.5280038Z def is_exception_branch(branch: str) -> bool: 2024-12-17T23:28:40.5280619Z """ 2024-12-17T23:28:40.5281370Z Branches that get opted out of experiments by default, until they're explicitly enabled. 2024-12-17T23:28:40.5282213Z """ 2024-12-17T23:28:40.5282804Z return branch.split("/")[0] in {"main", "nightly", "release", "landchecks"} 2024-12-17T23:28:40.5283349Z 2024-12-17T23:28:40.5283355Z 2024-12-17T23:28:40.5283631Z def load_yaml(yaml_text: str) -> Any: 2024-12-17T23:28:40.5284243Z try: 2024-12-17T23:28:40.5284665Z data = yaml.safe_load(yaml_text) 2024-12-17T23:28:40.5285284Z return data 2024-12-17T23:28:40.5285798Z except yaml.YAMLError: 2024-12-17T23:28:40.5286309Z log.exception("Error loading YAML") 2024-12-17T23:28:40.5286940Z raise 2024-12-17T23:28:40.5287248Z 2024-12-17T23:28:40.5287255Z 2024-12-17T23:28:40.5287679Z def extract_settings_user_opt_in_from_text(rollout_state: str) -> Tuple[str, str]: 2024-12-17T23:28:40.5288468Z """ 2024-12-17T23:28:40.5289159Z Extracts the text with settings, if any, and the opted in users from the rollout state. 2024-12-17T23:28:40.5289834Z 2024-12-17T23:28:40.5290192Z If the issue body contains "---" then the text above that is the settings 2024-12-17T23:28:40.5290991Z and the text below is the list of opted in users. 2024-12-17T23:28:40.5291391Z 2024-12-17T23:28:40.5291840Z If it doesn't contain "---" then the settings are empty and the rest is the users. 2024-12-17T23:28:40.5292780Z """ 2024-12-17T23:28:40.5293289Z rollout_state_parts = rollout_state.split("---") 2024-12-17T23:28:40.5293975Z if len(rollout_state_parts) >= 2: 2024-12-17T23:28:40.5294663Z return rollout_state_parts[0], rollout_state_parts[1] 2024-12-17T23:28:40.5295602Z else: 2024-12-17T23:28:40.5296152Z return "", rollout_state 2024-12-17T23:28:40.5296541Z 2024-12-17T23:28:40.5296548Z 2024-12-17T23:28:40.5296780Z class UserOptins(Dict[str, List[str]]): 2024-12-17T23:28:40.5297388Z """ 2024-12-17T23:28:40.5298049Z Dictionary of users with a list of features they have opted into 2024-12-17T23:28:40.5298729Z """ 2024-12-17T23:28:40.5298976Z 2024-12-17T23:28:40.5298983Z 2024-12-17T23:28:40.5299345Z def parse_user_opt_in_from_text(user_optin_text: str) -> UserOptins: 2024-12-17T23:28:40.5300114Z """ 2024-12-17T23:28:40.5300836Z 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:40.5301554Z 2024-12-17T23:28:40.5302182Z Users are GitHub usernames with the @ prefix. Each user is also a comma-separated list of features/experiments to enable. 2024-12-17T23:28:40.5303275Z - Example line: "@User1,lf,split_build" 2024-12-17T23:28:40.5303982Z - A "#" prefix indicates the user is opted out of all experiments 2024-12-17T23:28:40.5304521Z 2024-12-17T23:28:40.5304528Z 2024-12-17T23:28:40.5304705Z """ 2024-12-17T23:28:40.5305205Z optins = UserOptins() 2024-12-17T23:28:40.5305761Z for user in user_optin_text.split("\n"): 2024-12-17T23:28:40.5306354Z user = user.strip("\r\n\t -") 2024-12-17T23:28:40.5307023Z if not user or not user.startswith("@"): 2024-12-17T23:28:40.5307659Z # Not a valid user. Skip 2024-12-17T23:28:40.5308173Z continue 2024-12-17T23:28:40.5308519Z 2024-12-17T23:28:40.5308722Z if user: 2024-12-17T23:28:40.5309232Z usr_name = user.split(",")[0].strip("@") 2024-12-17T23:28:40.5309941Z optins[usr_name] = [exp.strip(" ") for exp in user.split(",")[1:]] 2024-12-17T23:28:40.5310515Z 2024-12-17T23:28:40.5310724Z return optins 2024-12-17T23:28:40.5310977Z 2024-12-17T23:28:40.5310982Z 2024-12-17T23:28:40.5311339Z def is_valid_experiment_name(experiment_name: str) -> bool: 2024-12-17T23:28:40.5312136Z """ 2024-12-17T23:28:40.5312707Z Check if the experiment name is valid. 2024-12-17T23:28:40.5313315Z A valid name: 2024-12-17T23:28:40.5313990Z - Contains only alphanumeric characters and the special characters "_" & "-" 2024-12-17T23:28:40.5315105Z - The special characters "_" & "-" shouldn't be the first or last characters 2024-12-17T23:28:40.5315867Z - Cannot contain spaces 2024-12-17T23:28:40.5316355Z """ 2024-12-17T23:28:40.5316652Z 2024-12-17T23:28:40.5316968Z valid_char_regex = r"^[a-zA-Z0-9]([\w-]*[a-zA-Z0-9])?$" 2024-12-17T23:28:40.5317727Z valid = bool(re.match(valid_char_regex, experiment_name)) 2024-12-17T23:28:40.5318187Z 2024-12-17T23:28:40.5318383Z if valid: 2024-12-17T23:28:40.5318901Z return True 2024-12-17T23:28:40.5319188Z 2024-12-17T23:28:40.5319373Z log.error( 2024-12-17T23:28:40.5320807Z 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:40.5322433Z ) 2024-12-17T23:28:40.5322868Z return False 2024-12-17T23:28:40.5323117Z 2024-12-17T23:28:40.5323123Z 2024-12-17T23:28:40.5323465Z def parse_settings_from_text(settings_text: str) -> Settings: 2024-12-17T23:28:40.5324203Z """ 2024-12-17T23:28:40.5324851Z Parse the experiments from the issue body into a list of ExperimentSettings 2024-12-17T23:28:40.5325616Z """ 2024-12-17T23:28:40.5326083Z try: 2024-12-17T23:28:40.5326525Z if settings_text: 2024-12-17T23:28:40.5327295Z # Escape the backtick as well so that we can have the settings in a code block on the GH issue 2024-12-17T23:28:40.5328408Z # for easy reading 2024-12-17T23:28:40.5329207Z # Note: Using ascii for the backtick so that the cat step in _runner-determinator.yml doesn't choke on 2024-12-17T23:28:40.5330139Z # the backtick character in shell commands. 2024-12-17T23:28:40.5330888Z backtick = chr(96) # backtick character 2024-12-17T23:28:40.5331590Z settings_text = settings_text.strip(f"\r\n\t{backtick} ") 2024-12-17T23:28:40.5332292Z settings = load_yaml(settings_text) 2024-12-17T23:28:40.5332731Z 2024-12-17T23:28:40.5333198Z # For now we just load experiments. We can expand this if/when we add more settings 2024-12-17T23:28:40.5333983Z experiments = {} 2024-12-17T23:28:40.5334333Z 2024-12-17T23:28:40.5334684Z for exp_name, exp_settings in settings.get(SETTING_EXPERIMENTS).items(): 2024-12-17T23:28:40.5336135Z if not is_valid_experiment_name(exp_name): 2024-12-17T23:28:40.5337303Z # 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:40.5338334Z continue 2024-12-17T23:28:40.5338753Z 2024-12-17T23:28:40.5338971Z valid_settings = {} 2024-12-17T23:28:40.5339568Z for setting in exp_settings: 2024-12-17T23:28:40.5340158Z if setting not in Experiment._fields: 2024-12-17T23:28:40.5340872Z log.warning( 2024-12-17T23:28:40.5341621Z f"Unexpected setting in experiment: {setting} = {exp_settings[setting]}" 2024-12-17T23:28:40.5342331Z ) 2024-12-17T23:28:40.5342922Z else: 2024-12-17T23:28:40.5343498Z valid_settings[setting] = exp_settings[setting] 2024-12-17T23:28:40.5343929Z 2024-12-17T23:28:40.5344224Z experiments[exp_name] = Experiment(**valid_settings) 2024-12-17T23:28:40.5345023Z return Settings(experiments) 2024-12-17T23:28:40.5345383Z 2024-12-17T23:28:40.5345618Z except Exception: 2024-12-17T23:28:40.5346141Z log.exception("Failed to parse settings") 2024-12-17T23:28:40.5346676Z 2024-12-17T23:28:40.5347027Z return Settings() 2024-12-17T23:28:40.5347351Z 2024-12-17T23:28:40.5347357Z 2024-12-17T23:28:40.5347625Z def parse_settings(rollout_state: str) -> Settings: 2024-12-17T23:28:40.5348323Z """ 2024-12-17T23:28:40.5348794Z Parse settings, if any, from the rollout state. 2024-12-17T23:28:40.5349231Z 2024-12-17T23:28:40.5349593Z If the issue body contains "---" then the text above that is the settings 2024-12-17T23:28:40.5350464Z and the text below is the list of opted in users. 2024-12-17T23:28:40.5350895Z 2024-12-17T23:28:40.5351302Z If it doesn't contain "---" then the settings are empty and the default values are used. 2024-12-17T23:28:40.5352090Z """ 2024-12-17T23:28:40.5352789Z settings_text, _ = extract_settings_user_opt_in_from_text(rollout_state) 2024-12-17T23:28:40.5353572Z return parse_settings_from_text(settings_text) 2024-12-17T23:28:40.5354016Z 2024-12-17T23:28:40.5354023Z 2024-12-17T23:28:40.5354298Z def parse_users(rollout_state: str) -> UserOptins: 2024-12-17T23:28:40.5354983Z """ 2024-12-17T23:28:40.5355462Z Parse users from the rollout state. 2024-12-17T23:28:40.5355819Z 2024-12-17T23:28:40.5356022Z """ 2024-12-17T23:28:40.5356646Z _, users_text = extract_settings_user_opt_in_from_text(rollout_state) 2024-12-17T23:28:40.5357437Z return parse_user_opt_in_from_text(users_text) 2024-12-17T23:28:40.5357838Z 2024-12-17T23:28:40.5357844Z 2024-12-17T23:28:40.5358274Z def is_user_opted_in(user: str, user_optins: UserOptins, experiment_name: str) -> bool: 2024-12-17T23:28:40.5359108Z """ 2024-12-17T23:28:40.5359597Z Check if a user is opted into an experiment 2024-12-17T23:28:40.5360339Z """ 2024-12-17T23:28:40.5360902Z return experiment_name in user_optins.get(user, []) 2024-12-17T23:28:40.5361339Z 2024-12-17T23:28:40.5361346Z 2024-12-17T23:28:40.5361822Z def is_user_opted_out(user: str, user_optins: UserOptins, experiment_name: str) -> bool: 2024-12-17T23:28:40.5362608Z """ 2024-12-17T23:28:40.5363146Z Check if a user explicitly opted out of an experiment 2024-12-17T23:28:40.5363826Z """ 2024-12-17T23:28:40.5364389Z # if the experiment is prefixed with a "-", then it's an opt-out 2024-12-17T23:28:40.5365128Z experiment_optout = "-" + experiment_name 2024-12-17T23:28:40.5365850Z if experiment_optout not in user_optins.get(user, []): 2024-12-17T23:28:40.5366500Z return False 2024-12-17T23:28:40.5366743Z 2024-12-17T23:28:40.5367085Z if is_user_opted_in(user, user_optins, experiment_name): 2024-12-17T23:28:40.5367774Z log.warning( 2024-12-17T23:28:40.5368603Z f"User {user} is opted into experiment {experiment_name}, but also opted out of it. Defaulting to opting out" 2024-12-17T23:28:40.5369532Z ) 2024-12-17T23:28:40.5369826Z 2024-12-17T23:28:40.5370013Z return True 2024-12-17T23:28:40.5370258Z 2024-12-17T23:28:40.5370264Z 2024-12-17T23:28:40.5370501Z def get_runner_prefix( 2024-12-17T23:28:40.5371009Z rollout_state: str, 2024-12-17T23:28:40.5371574Z workflow_requestors: Iterable[str], 2024-12-17T23:28:40.5372149Z branch: str, 2024-12-17T23:28:40.5372716Z eligible_experiments: FrozenSet[str] = frozenset(), 2024-12-17T23:28:40.5373383Z is_canary: bool = False, 2024-12-17T23:28:40.5373902Z ) -> str: 2024-12-17T23:28:40.5374402Z settings = parse_settings(rollout_state) 2024-12-17T23:28:40.5375049Z user_optins = parse_users(rollout_state) 2024-12-17T23:28:40.5375753Z 2024-12-17T23:28:40.5376003Z fleet_prefix = "" 2024-12-17T23:28:40.5376557Z prefixes = [] 2024-12-17T23:28:40.5377258Z for experiment_name, experiment_settings in settings.experiments.items(): 2024-12-17T23:28:40.5378261Z if not experiment_settings.all_branches and is_exception_branch(branch): 2024-12-17T23:28:40.5379077Z log.info( 2024-12-17T23:28:40.5379787Z f"Branch {branch} is an exception branch. Not enabling experiment {experiment_name}." 2024-12-17T23:28:40.5380739Z ) 2024-12-17T23:28:40.5381354Z continue 2024-12-17T23:28:40.5381655Z 2024-12-17T23:28:40.5381863Z if eligible_experiments: 2024-12-17T23:28:40.5382543Z if experiment_name not in eligible_experiments: 2024-12-17T23:28:40.5383242Z exp_list = ", ".join(eligible_experiments) 2024-12-17T23:28:40.5383837Z log.info( 2024-12-17T23:28:40.5384707Z f"Skipping experiment '{experiment_name}', as it is not in the eligible_experiments list: {exp_list}" 2024-12-17T23:28:40.5385611Z ) 2024-12-17T23:28:40.5386033Z continue 2024-12-17T23:28:40.5386612Z elif not experiment_settings.default: 2024-12-17T23:28:40.5387253Z log.info( 2024-12-17T23:28:40.5387920Z f"Skipping experiment '{experiment_name}', as it is not a default experiment" 2024-12-17T23:28:40.5388742Z ) 2024-12-17T23:28:40.5389216Z continue 2024-12-17T23:28:40.5389473Z 2024-12-17T23:28:40.5389766Z # Is any workflow_requestor opted out to this experiment? 2024-12-17T23:28:40.5390480Z opted_out_users = [ 2024-12-17T23:28:40.5391027Z requestor 2024-12-17T23:28:40.5391505Z for requestor in workflow_requestors 2024-12-17T23:28:40.5392273Z if is_user_opted_out(requestor, user_optins, experiment_name) 2024-12-17T23:28:40.5392997Z ] 2024-12-17T23:28:40.5393222Z 2024-12-17T23:28:40.5393417Z if opted_out_users: 2024-12-17T23:28:40.5393978Z log.info( 2024-12-17T23:28:40.5394700Z f"{', '.join(opted_out_users)} have opted out of experiment {experiment_name}." 2024-12-17T23:28:40.5395407Z ) 2024-12-17T23:28:40.5396081Z continue 2024-12-17T23:28:40.5396400Z 2024-12-17T23:28:40.5396678Z # Is any workflow_requestor opted in to this experiment? 2024-12-17T23:28:40.5397381Z opted_in_users = [ 2024-12-17T23:28:40.5397917Z requestor 2024-12-17T23:28:40.5398447Z for requestor in workflow_requestors 2024-12-17T23:28:40.5399173Z if is_user_opted_in(requestor, user_optins, experiment_name) 2024-12-17T23:28:40.5399856Z ] 2024-12-17T23:28:40.5400129Z 2024-12-17T23:28:40.5400321Z enabled = False 2024-12-17T23:28:40.5400834Z if opted_in_users: 2024-12-17T23:28:40.5401363Z log.info( 2024-12-17T23:28:40.5402020Z f"{', '.join(opted_in_users)} have opted into experiment {experiment_name}." 2024-12-17T23:28:40.5402756Z ) 2024-12-17T23:28:40.5403219Z enabled = True 2024-12-17T23:28:40.5403559Z 2024-12-17T23:28:40.5403790Z elif experiment_settings.rollout_perc: 2024-12-17T23:28:40.5404684Z # If no user is opted in, then we randomly enable the experiment based on the rollout percentage 2024-12-17T23:28:40.5405651Z if random.uniform(0, 100) <= experiment_settings.rollout_perc: 2024-12-17T23:28:40.5406372Z log.info( 2024-12-17T23:28:40.5407294Z f"Based on rollout percentage of {experiment_settings.rollout_perc}%, enabling experiment {experiment_name}." 2024-12-17T23:28:40.5408253Z ) 2024-12-17T23:28:40.5408739Z enabled = True 2024-12-17T23:28:40.5409063Z 2024-12-17T23:28:40.5409301Z if enabled: 2024-12-17T23:28:40.5409954Z label = experiment_name 2024-12-17T23:28:40.5410548Z if experiment_name == LF_FLEET_EXPERIMENT: 2024-12-17T23:28:40.5411399Z # We give some special treatment to the "lf" experiment since determines the fleet we use 2024-12-17T23:28:40.5412366Z # - If it's enabled, then we always list it's prefix first 2024-12-17T23:28:40.5413158Z # - If we're in the canary branch, then we append ".c" to the lf prefix 2024-12-17T23:28:40.5413861Z if is_canary: 2024-12-17T23:28:40.5414485Z label += CANARY_FLEET_SUFFIX 2024-12-17T23:28:40.5415076Z fleet_prefix = label 2024-12-17T23:28:40.5416286Z else: 2024-12-17T23:28:40.5416897Z prefixes.append(label) 2024-12-17T23:28:40.5417259Z 2024-12-17T23:28:40.5417462Z if len(prefixes) > 1: 2024-12-17T23:28:40.5417976Z log.error( 2024-12-17T23:28:40.5419098Z 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:40.5420207Z ) 2024-12-17T23:28:40.5420654Z prefixes = prefixes[:1] 2024-12-17T23:28:40.5420952Z 2024-12-17T23:28:40.5421285Z # Fleet always comes first 2024-12-17T23:28:40.5421787Z if fleet_prefix: 2024-12-17T23:28:40.5422299Z prefixes.insert(0, fleet_prefix) 2024-12-17T23:28:40.5422658Z 2024-12-17T23:28:40.5423037Z return ".".join(prefixes) + "." if prefixes else "" 2024-12-17T23:28:40.5423451Z 2024-12-17T23:28:40.5423458Z 2024-12-17T23:28:40.5423928Z def get_rollout_state_from_issue(github_token: str, repo: str, issue_num: int) -> str: 2024-12-17T23:28:40.5424726Z """ 2024-12-17T23:28:40.5425433Z Gets the first comment of the issue, which contains the desired rollout state. 2024-12-17T23:28:40.5425994Z 2024-12-17T23:28:40.5426422Z The default issue we use - https://github.com/pytorch/test-infra/issues/5132 2024-12-17T23:28:40.5427156Z """ 2024-12-17T23:28:40.5427665Z gh = get_gh_client(github_token) 2024-12-17T23:28:40.5428257Z issue = get_issue(gh, repo, issue_num) 2024-12-17T23:28:40.5428913Z return str(issue.get_comments()[0].body.strip("\n\t ")) 2024-12-17T23:28:40.5429435Z 2024-12-17T23:28:40.5429441Z 2024-12-17T23:28:40.5429863Z def download_json(url: str, headers: Dict[str, str], num_retries: int = 3) -> Any: 2024-12-17T23:28:40.5430833Z for _ in range(num_retries): 2024-12-17T23:28:40.5431327Z try: 2024-12-17T23:28:40.5431884Z req = Request(url=url, headers=headers) 2024-12-17T23:28:40.5432607Z content = urlopen(req, timeout=5).read().decode("utf-8") 2024-12-17T23:28:40.5433282Z return json.loads(content) 2024-12-17T23:28:40.5433904Z except Exception as e: 2024-12-17T23:28:40.5434526Z log.warning(f"Could not download {url}: {e}") 2024-12-17T23:28:40.5434925Z 2024-12-17T23:28:40.5435323Z log.warning(f"All {num_retries} retries exhausted, downloading {url} failed") 2024-12-17T23:28:40.5436115Z return {} 2024-12-17T23:28:40.5436400Z 2024-12-17T23:28:40.5436406Z 2024-12-17T23:28:40.5436599Z @lru_cache(maxsize=None) 2024-12-17T23:28:40.5437322Z def get_pr_info(github_repo: str, github_token: str, pr_number: int) -> Dict[str, Any]: 2024-12-17T23:28:40.5438160Z """ 2024-12-17T23:28:40.5438637Z Dynamically get PR information 2024-12-17T23:28:40.5439163Z """ 2024-12-17T23:28:40.5439774Z github_api = f"https://api.github.com/repos/{github_repo}" 2024-12-17T23:28:40.5440444Z headers = { 2024-12-17T23:28:40.5440943Z "Accept": "application/vnd.github.v3+json", 2024-12-17T23:28:40.5441665Z "Authorization": f"token {github_token}", 2024-12-17T23:28:40.5442267Z } 2024-12-17T23:28:40.5442733Z json_response: Dict[str, Any] = download_json( 2024-12-17T23:28:40.5443447Z url=f"{github_api}/issues/{pr_number}", 2024-12-17T23:28:40.5444048Z headers=headers, 2024-12-17T23:28:40.5444525Z ) 2024-12-17T23:28:40.5444825Z 2024-12-17T23:28:40.5445042Z if not json_response: 2024-12-17T23:28:40.5445657Z log.warning(f"Failed to get the labels for #{pr_number}") 2024-12-17T23:28:40.5446303Z return {} 2024-12-17T23:28:40.5446625Z 2024-12-17T23:28:40.5446835Z return json_response 2024-12-17T23:28:40.5447155Z 2024-12-17T23:28:40.5447168Z 2024-12-17T23:28:40.5447564Z def get_labels(github_repo: str, github_token: str, pr_number: int) -> Set[str]: 2024-12-17T23:28:40.5448320Z """ 2024-12-17T23:28:40.5448980Z Dynamically get the latest list of labels from the pull request 2024-12-17T23:28:40.5449637Z """ 2024-12-17T23:28:40.5450316Z pr_info = get_pr_info(github_repo, github_token, pr_number) 2024-12-17T23:28:40.5451083Z return { 2024-12-17T23:28:40.5451674Z label.get("name") for label in pr_info.get("labels", []) if label.get("name") 2024-12-17T23:28:40.5452417Z } 2024-12-17T23:28:40.5452701Z 2024-12-17T23:28:40.5452708Z 2024-12-17T23:28:40.5452949Z def main() -> None: 2024-12-17T23:28:40.5453401Z args = parse_args() 2024-12-17T23:28:40.5453717Z 2024-12-17T23:28:40.5453931Z runner_label_prefix = DEFAULT_LABEL_PREFIX 2024-12-17T23:28:40.5454393Z 2024-12-17T23:28:40.5454654Z # Check if the PR is opt-out 2024-12-17T23:28:40.5455178Z if args.pr_number: 2024-12-17T23:28:40.5456218Z labels = get_labels(args.github_repo, args.github_token, int(args.pr_number)) 2024-12-17T23:28:40.5457151Z if OPT_OUT_LABEL in labels: 2024-12-17T23:28:40.5457688Z log.info( 2024-12-17T23:28:40.5458399Z f"Opt-out runner determinator because #{args.pr_number} has {OPT_OUT_LABEL} label" 2024-12-17T23:28:40.5459307Z ) 2024-12-17T23:28:40.5459889Z set_github_output(GH_OUTPUT_KEY_LABEL_TYPE, runner_label_prefix) 2024-12-17T23:28:40.5460591Z sys.exit() 2024-12-17T23:28:40.5460973Z 2024-12-17T23:28:40.5461177Z try: 2024-12-17T23:28:40.5461664Z rollout_state = get_rollout_state_from_issue( 2024-12-17T23:28:40.5462357Z args.github_token, args.github_issue_repo, args.github_issue 2024-12-17T23:28:40.5463139Z ) 2024-12-17T23:28:40.5463360Z 2024-12-17T23:28:40.5463612Z username = get_potential_pr_author( 2024-12-17T23:28:40.5464150Z args.github_token, 2024-12-17T23:28:40.5464800Z args.github_repo, 2024-12-17T23:28:40.5465517Z args.github_actor, 2024-12-17T23:28:40.5466002Z args.github_ref_type, 2024-12-17T23:28:40.5466659Z args.github_branch, 2024-12-17T23:28:40.5467182Z ) 2024-12-17T23:28:40.5467403Z 2024-12-17T23:28:40.5467690Z is_canary = args.github_repo == "pytorch/pytorch-canary" 2024-12-17T23:28:40.5468279Z 2024-12-17T23:28:40.5468515Z runner_label_prefix = get_runner_prefix( 2024-12-17T23:28:40.5469129Z rollout_state, 2024-12-17T23:28:40.5469628Z (args.github_issue_owner, username), 2024-12-17T23:28:40.5470371Z args.github_branch, 2024-12-17T23:28:40.5470927Z args.eligible_experiments, 2024-12-17T23:28:40.5471466Z is_canary, 2024-12-17T23:28:40.5472018Z ) 2024-12-17T23:28:40.5472237Z 2024-12-17T23:28:40.5472470Z except Exception as e: 2024-12-17T23:28:40.5472955Z log.error( 2024-12-17T23:28:40.5473739Z f"Failed to get issue. Defaulting to Meta runners and no experiments. Exception: {e}" 2024-12-17T23:28:40.5474565Z ) 2024-12-17T23:28:40.5474788Z 2024-12-17T23:28:40.5475103Z set_github_output(GH_OUTPUT_KEY_LABEL_TYPE, runner_label_prefix) 2024-12-17T23:28:40.5475719Z 2024-12-17T23:28:40.5475725Z 2024-12-17T23:28:40.5475924Z if __name__ == "__main__": 2024-12-17T23:28:40.5476442Z main() 2024-12-17T23:28:40.5476667Z 2024-12-17T23:28:40.5567224Z ##[group]Run python3 -m pip install urllib3==1.26.18 PyGithub==2.3.0 2024-12-17T23:28:40.5568159Z python3 -m pip install urllib3==1.26.18 PyGithub==2.3.0 2024-12-17T23:28:40.5621570Z shell: /usr/bin/bash -e {0} 2024-12-17T23:28:40.5622200Z env: 2024-12-17T23:28:40.5622862Z GITHUB_TOKEN: *** 2024-12-17T23:28:40.5623355Z ISSUE_NUMBER: 5132 2024-12-17T23:28:40.5623917Z TRIGGERING_ACTOR: malfet 2024-12-17T23:28:40.5624414Z ISSUE_OWNER: 2024-12-17T23:28:40.5624887Z CHECK_EXPERIMENTS: 2024-12-17T23:28:40.5625445Z PR_NUMBER: 2024-12-17T23:28:40.5625889Z ##[endgroup] 2024-12-17T23:28:41.5301188Z Defaulting to user installation because normal site-packages is not writeable 2024-12-17T23:28:42.1314839Z Collecting urllib3==1.26.18 2024-12-17T23:28:42.1873464Z Downloading urllib3-1.26.18-py2.py3-none-any.whl (143 kB) 2024-12-17T23:28:42.2224402Z ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 143.8/143.8 KB 5.7 MB/s eta 0:00:00 2024-12-17T23:28:42.2459514Z Collecting PyGithub==2.3.0 2024-12-17T23:28:42.2579649Z Downloading PyGithub-2.3.0-py3-none-any.whl (354 kB) 2024-12-17T23:28:42.2898504Z ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 354.4/354.4 KB 11.5 MB/s eta 0:00:00 2024-12-17T23:28:42.3404277Z Collecting pyjwt[crypto]>=2.4.0 2024-12-17T23:28:42.3494885Z Downloading PyJWT-2.10.1-py3-none-any.whl (22 kB) 2024-12-17T23:28:42.3527801Z 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:42.3754059Z Collecting Deprecated 2024-12-17T23:28:42.3843508Z Downloading Deprecated-1.2.15-py2.py3-none-any.whl (9.9 kB) 2024-12-17T23:28:42.4137469Z Collecting typing-extensions>=4.0.0 2024-12-17T23:28:42.4248387Z Downloading typing_extensions-4.12.2-py3-none-any.whl (37 kB) 2024-12-17T23:28:42.4789853Z Collecting pynacl>=1.4.0 2024-12-17T23:28:42.4881255Z 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:42.5485821Z ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 856.7/856.7 KB 14.5 MB/s eta 0:00:00 2024-12-17T23:28:42.5611943Z 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:42.7943718Z Collecting cffi>=1.4.1 2024-12-17T23:28:42.8033577Z Downloading cffi-1.17.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (446 kB) 2024-12-17T23:28:42.8298647Z ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 446.2/446.2 KB 17.9 MB/s eta 0:00:00 2024-12-17T23:28:43.0361127Z Collecting wrapt<2,>=1.10 2024-12-17T23:28:43.0454246Z 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:43.0498586Z ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 82.7/82.7 KB 28.8 MB/s eta 0:00:00 2024-12-17T23:28:43.0662070Z Collecting pycparser 2024-12-17T23:28:43.0749799Z Downloading pycparser-2.22-py3-none-any.whl (117 kB) 2024-12-17T23:28:43.0822153Z ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 117.6/117.6 KB 20.5 MB/s eta 0:00:00 2024-12-17T23:28:43.3619565Z Installing collected packages: wrapt, urllib3, typing-extensions, pyjwt, pycparser, Deprecated, cffi, pynacl, PyGithub 2024-12-17T23:28:43.8278578Z 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:43.8941046Z ##[group]Run curr_branch="release/2.6" 2024-12-17T23:28:43.8941658Z curr_branch="release/2.6" 2024-12-17T23:28:43.8942036Z curr_ref_type="branch" 2024-12-17T23:28:43.8942400Z echo "Current branch is '$curr_branch'" 2024-12-17T23:28:43.8942880Z  2024-12-17T23:28:43.8943190Z python3 runner_determinator.py \ 2024-12-17T23:28:43.8943546Z  --github-token "$GITHUB_TOKEN" \ 2024-12-17T23:28:43.8943989Z  --github-issue "$ISSUE_NUMBER" \ 2024-12-17T23:28:43.8944381Z  --github-branch "$curr_branch" \ 2024-12-17T23:28:43.8944729Z  --github-actor "$TRIGGERING_ACTOR" \ 2024-12-17T23:28:43.8945177Z  --github-issue-owner "$ISSUE_OWNER" \ 2024-12-17T23:28:43.8945576Z  --github-ref-type "$curr_ref_type" \ 2024-12-17T23:28:43.8945936Z  --github-repo "$GITHUB_REPOSITORY" \ 2024-12-17T23:28:43.8946396Z  --eligible-experiments "$CHECK_EXPERIMENTS" \ 2024-12-17T23:28:43.8946908Z  --pr-number "${PR_NUMBER}" 2024-12-17T23:28:43.9004559Z shell: /usr/bin/bash -e {0} 2024-12-17T23:28:43.9004902Z env: 2024-12-17T23:28:43.9005688Z GITHUB_TOKEN: *** 2024-12-17T23:28:43.9006038Z ISSUE_NUMBER: 5132 2024-12-17T23:28:43.9006318Z TRIGGERING_ACTOR: malfet 2024-12-17T23:28:43.9006687Z ISSUE_OWNER: 2024-12-17T23:28:43.9006985Z CHECK_EXPERIMENTS: 2024-12-17T23:28:43.9007256Z PR_NUMBER: 2024-12-17T23:28:43.9007578Z ##[endgroup] 2024-12-17T23:28:43.9083219Z Current branch is 'release/2.6' 2024-12-17T23:28:45.2482004Z INFO : Based on rollout percentage of 95%, enabling experiment lf. 2024-12-17T23:28:45.2483799Z INFO : Skipping experiment 'awsa100', as it is not a default experiment 2024-12-17T23:28:45.2485205Z INFO : Setting output: label-type='lf.' 2024-12-17T23:28:45.2760573Z Evaluate and set job outputs 2024-12-17T23:28:45.2767507Z Set output 'label-type' 2024-12-17T23:28:45.2769455Z Cleaning up orphan processes