music on atproto
plyr.fm
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())