2026-01-10 06:00:48 +07:00
|
|
|
#!/usr/bin/env python3
|
|
|
|
|
"""
|
|
|
|
|
Script to merge best PRs and close duplicates
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
import subprocess
|
|
|
|
|
import sys
|
2026-01-21 16:23:19 +00:00
|
|
|
import concurrent.futures
|
2026-01-10 06:00:48 +07:00
|
|
|
from pathlib import Path
|
|
|
|
|
|
|
|
|
|
REPO_ROOT = Path(__file__).resolve().parents[1]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def run_command(cmd, check=True):
|
|
|
|
|
"""Run a command."""
|
|
|
|
|
try:
|
|
|
|
|
result = subprocess.run(
|
|
|
|
|
cmd,
|
|
|
|
|
cwd=REPO_ROOT,
|
|
|
|
|
capture_output=True,
|
|
|
|
|
text=True,
|
|
|
|
|
timeout=30,
|
|
|
|
|
encoding='utf-8',
|
|
|
|
|
errors='replace'
|
|
|
|
|
)
|
|
|
|
|
if check and result.returncode != 0:
|
|
|
|
|
print(f"Error: {result.stderr}", file=sys.stderr)
|
|
|
|
|
return None
|
|
|
|
|
return result.stdout
|
|
|
|
|
except Exception as e:
|
|
|
|
|
print(f"Error: {e}", file=sys.stderr)
|
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def merge_pr(pr_number, method="squash"):
|
|
|
|
|
"""Merge a PR."""
|
|
|
|
|
print(f"Merging PR #{pr_number}...")
|
|
|
|
|
result = run_command(["gh", "pr", "merge", str(pr_number), f"--{method}", "--delete-branch=false"], check=False)
|
|
|
|
|
if result:
|
|
|
|
|
print(f"✓ PR #{pr_number} merged successfully")
|
|
|
|
|
return True
|
|
|
|
|
else:
|
|
|
|
|
print(f"✗ Failed to merge PR #{pr_number}")
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def close_pr(pr_number, comment):
|
|
|
|
|
"""Close a PR with a comment."""
|
|
|
|
|
print(f"Closing PR #{pr_number}...")
|
|
|
|
|
result = run_command(["gh", "pr", "close", str(pr_number), "--comment", comment], check=False)
|
|
|
|
|
if result:
|
|
|
|
|
print(f"✓ PR #{pr_number} closed")
|
|
|
|
|
return True
|
|
|
|
|
else:
|
|
|
|
|
print(f"✗ Failed to close PR #{pr_number}")
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def main():
|
|
|
|
|
"""Main function."""
|
|
|
|
|
print("=" * 80)
|
|
|
|
|
print("PR MERGE AND CONSOLIDATION")
|
|
|
|
|
print("=" * 80)
|
|
|
|
|
print()
|
|
|
|
|
|
|
|
|
|
# Step 1: Merge best PRs
|
|
|
|
|
print("Step 1: Merging best PRs...")
|
|
|
|
|
print()
|
|
|
|
|
|
|
|
|
|
# PR #76: Early exit optimization
|
|
|
|
|
if merge_pr(76):
|
|
|
|
|
print(" ✓ PR #76 merged")
|
|
|
|
|
else:
|
|
|
|
|
print(" ✗ PR #76 merge failed or already merged")
|
|
|
|
|
|
|
|
|
|
# PR #75: New bar check + CopyRates optimization
|
|
|
|
|
if merge_pr(75):
|
|
|
|
|
print(" ✓ PR #75 merged")
|
|
|
|
|
else:
|
|
|
|
|
print(" ✗ PR #75 merge failed or already merged")
|
|
|
|
|
|
|
|
|
|
print()
|
|
|
|
|
|
|
|
|
|
# Step 2: Close duplicates
|
|
|
|
|
print("Step 2: Closing duplicate PRs...")
|
|
|
|
|
print()
|
|
|
|
|
|
|
|
|
|
# New bar check duplicates (if PR #75 merged)
|
|
|
|
|
new_bar_duplicates = [74, 73, 72, 71, 70, 69, 65, 62, 58, 57, 56, 54, 52]
|
2026-01-21 16:23:19 +00:00
|
|
|
|
2026-01-10 06:00:48 +07:00
|
|
|
# Early exit duplicates (if PR #76 merged)
|
|
|
|
|
early_exit_duplicates = [65, 56, 54] # Note: some overlap with new_bar
|
2026-01-21 16:23:19 +00:00
|
|
|
|
|
|
|
|
# Collect all PRs to close
|
|
|
|
|
tasks = []
|
|
|
|
|
for pr_num in new_bar_duplicates:
|
|
|
|
|
tasks.append((pr_num, "Merged via PR #75 - New bar check optimization"))
|
|
|
|
|
|
2026-01-10 06:00:48 +07:00
|
|
|
for pr_num in early_exit_duplicates:
|
|
|
|
|
if pr_num not in new_bar_duplicates: # Don't close twice
|
2026-01-21 16:23:19 +00:00
|
|
|
tasks.append((pr_num, "Merged via PR #76 - Early exit optimization"))
|
|
|
|
|
|
|
|
|
|
# Execute in parallel to mask network latency
|
|
|
|
|
with concurrent.futures.ThreadPoolExecutor(max_workers=10) as executor:
|
|
|
|
|
futures = {executor.submit(close_pr, pr, msg): pr for pr, msg in tasks}
|
|
|
|
|
concurrent.futures.wait(futures)
|
2026-01-10 06:00:48 +07:00
|
|
|
|
|
|
|
|
print()
|
|
|
|
|
print("=" * 80)
|
|
|
|
|
print("CONSOLIDATION COMPLETE")
|
|
|
|
|
print("=" * 80)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
|
main()
|