/ dev / create_release_branch.py
create_release_branch.py
 1  import argparse
 2  import os
 3  import subprocess
 4  
 5  from packaging.version import Version
 6  
 7  
 8  def main(new_version: str, remote: str, dry_run: bool = False) -> None:
 9      version = Version(new_version)
10      release_branch = f"branch-{version.major}.{version.minor}"
11      exists_on_remote = (
12          subprocess.check_output(
13              ["git", "ls-remote", "--heads", remote, release_branch], text=True
14          ).strip()
15          != ""
16      )
17      if exists_on_remote:
18          print(f"{release_branch} already exists on {remote}, skipping branch creation")
19          return
20  
21      prev_branch = subprocess.check_output(["git", "branch", "--show-current"], text=True).strip()
22      try:
23          exists_on_local = (
24              subprocess.check_output(["git", "branch", "--list", release_branch], text=True).strip()
25              != ""
26          )
27          if exists_on_local:
28              print(f"Deleting existing {release_branch}")
29              subprocess.check_call(["git", "branch", "-D", release_branch])
30  
31          print(f"Creating {release_branch}")
32          subprocess.check_call(["git", "checkout", "-b", release_branch, "master"])
33          print(f"Pushing {release_branch} to {remote}")
34          subprocess.check_call([
35              "git",
36              "push",
37              remote,
38              release_branch,
39              *(["--dry-run"] if dry_run else []),
40          ])
41      finally:
42          subprocess.check_call(["git", "checkout", prev_branch])
43  
44  
45  if __name__ == "__main__":
46      parser = argparse.ArgumentParser(description="Create a release branch")
47      parser.add_argument("--new-version", required=True, help="New version to release")
48      parser.add_argument("--remote", default="origin", help="Git remote to use (default: origin)")
49      parser.add_argument(
50          "--dry-run",
51          action="store_true",
52          default=os.environ.get("DRY_RUN", "true").lower() == "true",
53          help="Dry run mode (default: True, can be set via DRY_RUN env var)",
54      )
55      parser.add_argument(
56          "--no-dry-run",
57          action="store_false",
58          dest="dry_run",
59          help="Disable dry run mode",
60      )
61      args = parser.parse_args()
62      main(args.new_version, args.remote, args.dry_run)