Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
92 changes: 70 additions & 22 deletions ci_scripts/update_doc.py
Original file line number Diff line number Diff line change
Expand Up @@ -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/<branch> 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():
Expand Down Expand Up @@ -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(
Expand All @@ -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:
Expand All @@ -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.",
],
Expand Down
Loading