+1
-5
backend/justfile
+1
-5
backend/justfile
backend/scripts/backfill_atproto_records.py
scripts/backfill_atproto_records.py
backend/scripts/backfill_atproto_records.py
scripts/backfill_atproto_records.py
backend/scripts/backfill_image_urls.py
scripts/backfill_image_urls.py
backend/scripts/backfill_image_urls.py
scripts/backfill_image_urls.py
backend/scripts/copy_r2_buckets.py
scripts/copy_r2_buckets.py
backend/scripts/copy_r2_buckets.py
scripts/copy_r2_buckets.py
backend/scripts/delete_track.py
scripts/delete_track.py
backend/scripts/delete_track.py
scripts/delete_track.py
backend/scripts/generate_audio_sample.py
scripts/generate_audio_sample.py
backend/scripts/generate_audio_sample.py
scripts/generate_audio_sample.py
backend/scripts/migrate_atproto_namespace.py
scripts/migrate_atproto_namespace.py
backend/scripts/migrate_atproto_namespace.py
scripts/migrate_atproto_namespace.py
backend/scripts/migrate_images_to_new_buckets.py
scripts/migrate_images_to_new_buckets.py
backend/scripts/migrate_images_to_new_buckets.py
scripts/migrate_images_to_new_buckets.py
backend/scripts/migrate_r2_bucket.py
scripts/migrate_r2_bucket.py
backend/scripts/migrate_r2_bucket.py
scripts/migrate_r2_bucket.py
-122
backend/scripts/release
-122
backend/scripts/release
···
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
-
8
-
version format: YYYY.MMDD.HHMMSS (e.g., 2025.1106.134523)
9
-
10
-
usage:
11
-
just release
12
-
./scripts/release
13
-
"""
14
-
15
-
import subprocess
16
-
import sys
17
-
from datetime import UTC, datetime
18
-
19
-
20
-
def 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", "--", "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
-
121
-
if __name__ == "__main__":
122
-
sys.exit(main())
backend/scripts/run_migration.py
scripts/run_migration.py
backend/scripts/run_migration.py
scripts/run_migration.py
backend/scripts/simulate_broken_tracks.py
scripts/simulate_broken_tracks.py
backend/scripts/simulate_broken_tracks.py
scripts/simulate_broken_tracks.py
backend/scripts/smoke_test_staging.py
scripts/smoke_test_staging.py
backend/scripts/smoke_test_staging.py
scripts/smoke_test_staging.py
backend/scripts/test-transcoder.sh
scripts/test-transcoder.sh
backend/scripts/test-transcoder.sh
scripts/test-transcoder.sh
+5
-1
justfile
+5
-1
justfile
···
23
23
changelog:
24
24
@git log $(git describe --tags --abbrev=0)..HEAD --pretty=format:'%C(yellow)%h%Creset %C(blue)%ad%Creset %C(green)%s%Creset %C(dim)- %an%Creset' --date=relative
25
25
26
+
# create a github release (triggers production deployment)
27
+
release:
28
+
./scripts/release
29
+
26
30
# deploy frontend only (promote remote main to production-fe branch)
27
31
release-frontend-only:
28
32
git fetch origin main
29
-
git push origin origin/main:production-fe
33
+
git push origin origin/main:production-fe
+122
scripts/release
+122
scripts/release
···
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
+
8
+
version format: YYYY.MMDD.HHMMSS (e.g., 2025.1106.134523)
9
+
10
+
usage:
11
+
just release
12
+
./scripts/release
13
+
"""
14
+
15
+
import subprocess
16
+
import sys
17
+
from datetime import UTC, datetime
18
+
19
+
20
+
def 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
+
121
+
if __name__ == "__main__":
122
+
sys.exit(main())