transformers-triage / code /run_queue.py
ArthurZ's picture
ArthurZ HF Staff
Add triage pipeline code
cc857c8 verified
Raw History Blame Contribute Delete
5.03 kB
import json, re, subprocess, sys, time, os
Q = json.load(open(sys.argv[1])); LOG = sys.argv[2] if len(sys.argv) > 2 else 'final_run.log'
done = set(re.findall(r'(issue|pr)#(\d+) (\w+)(?: \S+)? ok', open(LOG).read())) if os.path.exists(LOG) else set()
Q = [q for q in Q if (q['kind'], str(q['n']), q['op']) not in done]
N, t0, fails = len(Q), time.time(), []
log = open(LOG, 'a')
def p(s): log.write(s + '\n'); log.flush()
def already_posted(q):
try:
r = subprocess.run(['gh', q['kind'], 'view', str(q['n']), '-R', 'huggingface/transformers', '--json', 'comments,state',
'--jq', '[.state, (.comments[-1].author.login // ""), (.comments[-1].body // "")]'],
capture_output=True, text=True, timeout=60)
st, who, body = json.loads(r.stdout)
return who == 'ArthurZucker' and body.strip() == q['msg'].strip(), st
except Exception:
return False, None
def edit_ours(q):
qq = '{repository(owner:"huggingface",name:"transformers"){issueOrPullRequest(number:%d){... on Issue{comments(last:30){nodes{databaseId author{login} createdAt}}} ... on PullRequest{comments(last:30){nodes{databaseId author{login} createdAt}}}}}}' % q['n']
r = subprocess.run(['gh', 'api', 'graphql', '-f', 'query=' + qq], capture_output=True, text=True, timeout=60)
nodes = json.loads(r.stdout)['data']['repository']['issueOrPullRequest']['comments']['nodes']
ours = [x for x in nodes if (x['author'] or {}).get('login') == 'ArthurZucker' and x['createdAt'] >= '2026-10-20']
if not ours: return subprocess.CompletedProcess([], 1, '', 'no close comment from 2026-10-20+ to edit')
return subprocess.run(['gh', 'api', '-X', 'PATCH', f"repos/huggingface/transformers/issues/comments/{ours[-1]['databaseId']}", '-f', 'body=' + q['msg']],
capture_output=True, text=True, timeout=60)
for i, q in enumerate(Q, 1):
if q['op'] == 'addrev':
try: r = subprocess.run(['gh', 'pr', 'edit', str(q['n']), '-R', 'huggingface/transformers', '--add-reviewer', q['reviewer']], capture_output=True, text=True, timeout=60)
except Exception as e: r = subprocess.CompletedProcess([], 1, '', str(e))
time.sleep(2); el = time.time() - t0
if r.returncode == 0: p(f'[{i}/{N}] {q["kind"]}#{q["n"]} addrev {q["reviewer"]} ok | elapsed {el:.0f}s')
else: fails.append((q['kind'], q['n'], 'addrev: ' + (r.stderr or r.stdout)[:200])); p(f'[{i}/{N}] {q["kind"]}#{q["n"]} FAIL addrev {q["reviewer"]}: {(r.stderr or r.stdout)[:200]}')
continue
if q['op'] == 'edit':
try: r = edit_ours(q)
except Exception as e: r = subprocess.CompletedProcess([], 1, '', str(e))
time.sleep(4); el = time.time() - t0
if r.returncode == 0: p(f'[{i}/{N}] {q["kind"]}#{q["n"]} edit ok | elapsed {el:.0f}s')
else: fails.append((q['kind'], q['n'], (r.stderr or r.stdout)[:200])); p(f'[{i}/{N}] {q["kind"]}#{q["n"]} FAIL: {(r.stderr or r.stdout)[:200]}')
continue
posted, st = already_posted(q)
if posted and (q['op'] == 'comment' or st != 'OPEN'):
p(f'[{i}/{N}] {q["kind"]}#{q["n"]} {q["op"]} ok (already posted) | elapsed {time.time()-t0:.0f}s'); continue
cmd = ['gh', q['kind'], q['op'], str(q['n']), '-R', 'huggingface/transformers']
if q['op'] == 'close': cmd += (['-r', q['reason']] if q['kind'] == 'issue' else []) + ([] if posted else ['-c', q['msg']]) # comment already there → close only
else: cmd += ['-b', q['msg']]
for attempt in range(1000):
try:
r = subprocess.run(cmd, capture_output=True, text=True, timeout=120); out = r.stderr + r.stdout
except subprocess.TimeoutExpired:
p(f'[{i}/{N}] {q["kind"]}#{q["n"]} timeout, retrying in 30s'); time.sleep(30)
posted, st = already_posted(q) # the timed-out call may have gone through
if posted and (q['op'] == 'comment' or st != 'OPEN'):
r = subprocess.CompletedProcess(cmd, 0, '', ''); break
if posted and '-c' in cmd: cmd = cmd[:cmd.index('-c')]
continue
if r.returncode == 0: break
if 'too quickly' in out or 'rate limit' in out.lower():
p(f'[{i}/{N}] {q["kind"]}#{q["n"]} rate-limited, sleeping 300s'); time.sleep(300); continue
if ('Something went wrong' in out or 'timed out' in out or 'connection' in out.lower()) and attempt < 20: # transient network / GitHub 5xx
time.sleep(30); continue
break
time.sleep(4) # ponytail: fixed spacing under GitHub's content-creation limit
el = time.time() - t0
if r.returncode == 0: p(f'[{i}/{N}] {q["kind"]}#{q["n"]} {q["op"]} ok | elapsed {el:.0f}s | eta ~{el/i*(N-i):.0f}s')
else:
err = out.strip().replace('\n', ' ')[:200]; fails.append((q['kind'], q['n'], err)); p(f'[{i}/{N}] {q["kind"]}#{q["n"]} FAIL: {err}')
p(f'done {sys.argv[1]} ok={N-len(fails)} fails={len(fails)}')
json.dump(fails, open(sys.argv[1].replace('.json', '_fails.json'), 'w'))