at main 3.7 kB view raw
1#!/usr/bin/env -S uv run --script --quiet 2# /// script 3# requires-python = ">=3.12" 4# dependencies = [] 5# /// 6"""create a github release using timestamp-based versioning 7 8version format: YYYY.MMDD.HHMMSS (e.g., 2025.1106.134523) 9 10usage: 11 just release 12 ./scripts/release 13""" 14 15import subprocess 16import sys 17from datetime import UTC, datetime 18 19 20def main() -> int: 21 """create release with timestamp version.""" 22 # ensure we're on main branch 23 result = subprocess.run( 24 ["git", "branch", "--show-current"], 25 capture_output=True, 26 text=True, 27 check=True, 28 ) 29 current_branch = result.stdout.strip() 30 31 if current_branch != "main": 32 print(f"❌ must be on main branch (currently on {current_branch})") 33 return 1 34 35 # ensure working directory is clean 36 result = subprocess.run( 37 ["git", "status", "--porcelain"], 38 capture_output=True, 39 text=True, 40 check=True, 41 ) 42 if result.stdout.strip(): 43 print("❌ working directory has uncommitted changes") 44 return 1 45 46 # ensure we're up to date with remote 47 subprocess.run(["git", "fetch"], capture_output=True, check=True) 48 result = subprocess.run( 49 ["git", "rev-list", "HEAD..@{u}"], 50 capture_output=True, 51 text=True, 52 check=True, 53 ) 54 if result.stdout.strip(): 55 print("❌ local branch is behind remote - please pull first") 56 return 1 57 58 # check if there are backend changes since last release 59 result = subprocess.run( 60 ["gh", "release", "list", "--limit", "1"], 61 capture_output=True, 62 text=True, 63 check=True, 64 ) 65 if result.stdout.strip(): 66 last_release = result.stdout.split()[0] 67 68 # check for backend changes since last release 69 result = subprocess.run( 70 ["git", "log", f"{last_release}..HEAD", "--oneline", "--", "backend/src/backend/"], 71 capture_output=True, 72 text=True, 73 check=True, 74 ) 75 76 if not result.stdout.strip(): 77 print("❌ no backend changes since last release") 78 print(f" last release: {last_release}") 79 print(" only frontend/docs changes do not require a backend release") 80 return 1 81 82 version = datetime.now(UTC).strftime("%Y.%m%d.%H%M%S") 83 84 # print banner using figlet 85 subprocess.run(["figlet", "-f", "small", "plyr.fm"], check=False) 86 print("───────────────────────────") 87 print(f"release {version}") 88 print("target production") 89 print("───────────────────────────") 90 91 # create release - gh will auto-generate notes from commits 92 subprocess.run( 93 [ 94 "gh", 95 "release", 96 "create", 97 version, 98 "--title", 99 version, 100 "--generate-notes", 101 ], 102 check=True, 103 ) 104 105 print(f"\n✓ release {version} created") 106 print("✓ production backend deployment starting...") 107 108 # merge main -> production-fe to trigger frontend deployment 109 print("\n🔄 updating production-fe branch...") 110 subprocess.run(["git", "fetch", "origin"], check=True) 111 subprocess.run(["git", "checkout", "production-fe"], check=True) 112 subprocess.run(["git", "merge", "main", "--ff-only"], check=True) 113 subprocess.run(["git", "push", "origin", "production-fe"], check=True) 114 subprocess.run(["git", "checkout", "main"], check=True) 115 116 print("✓ production frontend deployment starting...") 117 118 return 0 119 120 121if __name__ == "__main__": 122 sys.exit(main())