diff --git a/ci_scripts/update_doc.py b/ci_scripts/update_doc.py index ab0e979ca..25c5024fa 100644 --- a/ci_scripts/update_doc.py +++ b/ci_scripts/update_doc.py @@ -224,8 +224,39 @@ def add_to_packages_file(slug): PACKAGES_FILE.write_text("\n".join(header + entries) + "\n") -def git_run(*args): - subprocess.run(["git", *args], check=True) +def git_run(*args, check=True): + return subprocess.run(["git", *args], check=check) + + +def checkout_shared_branch(branch): + """ + Check out the shared docs branch as a local worktree HEAD, based on + origin/ if it already exists, otherwise on origin/main. + + All docs updates are pushed to this single branch, so a run needs to build + on whatever is already there rather than starting from main each time. + """ + git_run("fetch", "origin") + remote_ref = f"origin/{branch}" + exists = git_run("rev-parse", "--verify", "--quiet", remote_ref, check=False).returncode == 0 + base = remote_ref if exists else "origin/main" + git_run("switch", "--force-create", branch, base) + + +def pr_exists(branch): + """Return True if an open PR already targets this branch as its head.""" + out = subprocess.run( + [ + "gh", "pr", "list", + "--repo", REPO, + "--head", branch, + "--state", "open", + "--json", "number", + "--jq", "length", + ], + capture_output=True, text=True, check=True, + ).stdout.strip() + return out.isdigit() and int(out) > 0 def configure_git_identity(): @@ -261,24 +292,30 @@ def main(): patch_dir = find_patch_dir(slug, version) comment = render_gpl_sources_comment() yaml_path = DOCS_DIR / f"{slug}.yaml" - is_new = not yaml_path.exists() - old_content = None if is_new else yaml_path.read_text() - if is_new: - new_content = render_new_yaml(slug, source_code, license, version, patch_dir, comment) - else: - package_data = yaml.safe_load(old_content) or {} - new_content = append_version( - old_content, package_data, version, license, patch_dir, comment - ) - if new_content is None: - print(f"{slug} {version} is already documented; nothing to do") - return + branch = "github-actions/update-doc" + pr_title = "docs: Update projects" - branch = f"github-actions/{'add' if is_new else 'update'}-doc-for-{slug}" - pr_title = f"docs: {'add' if is_new else 'update'} {slug}" + def compute_content(): + """Read the current YAML (if any) and return (is_new, old_content, new_content).""" + is_new = not yaml_path.exists() + old_content = None if is_new else yaml_path.read_text() + if is_new: + new_content = render_new_yaml( + slug, source_code, license, version, patch_dir, comment + ) + else: + package_data = yaml.safe_load(old_content) or {} + new_content = append_version( + old_content, package_data, version, license, patch_dir, comment + ) + return is_new, old_content, new_content if DRY_RUN: + is_new, old_content, new_content = compute_content() + if new_content is None: + print(f"{slug} {version} is already documented; nothing to do") + return print("[dry-run] Not on main branch — no branch, commit, or PR will be created.") print(f"[dry-run] Would write {yaml_path}:") diff = difflib.unified_diff( @@ -293,10 +330,17 @@ def main(): print(f"[dry-run] Would open PR '{pr_title}' from branch '{branch}' against main") return - yaml_path.write_text(new_content) configure_git_identity() + checkout_shared_branch(branch) + + # Compute the change against the shared branch's contents, so a package + # already documented there by an earlier run in this batch is seen. + is_new, _old_content, new_content = compute_content() + if new_content is None: + print(f"{slug} {version} is already documented; nothing to do") + return - git_run("switch", "-c", branch) + yaml_path.write_text(new_content) git_run("add", str(yaml_path)) if is_new: @@ -306,18 +350,22 @@ def main(): else: git_run("commit", "-s", "-m", f"docs: update {slug}\n\nAdd version {version}") - git_run("push", "origin", branch) + git_run("push", "origin", f"HEAD:{branch}") + + if pr_exists(branch): + print(f"[+] PR already open for branch '{branch}'; pushed update") + return result = subprocess.run( [ - "gh", "pr", "create", "--draft", + "gh", "pr", "create", "--repo", REPO, "--base", "main", "--head", branch, - "--reviewer", "threexc,justeph", + "--reviewer", "threexc,justeph,luhenry", "--title", pr_title, "--body", - "Automatically generated PR to document a newly published wheel. " + "Automatically generated PR to document newly published wheels. " "Please review it carefully before merging.\n\n" "If necessary, force-push this branch.", ],