Skip to content

Commit 3054624

Browse files
committed
Add tag-and-push script for easy test releases
- Automatically reads version from setup.py - Creates tags in format vX.Y.Z-testN - Auto-increments test number or accepts manual input - Pushes tag to trigger TestPyPI workflow - Includes help and usage examples
1 parent 3397d77 commit 3054624

2 files changed

Lines changed: 118 additions & 1 deletion

File tree

‎scripts/tag-and-push‎

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
#!/usr/bin/env python3
2+
"""
3+
Create and push a test tag based on the current project version.
4+
Usage: ./tag-and-push [N]
5+
Where N is the test number (defaults to 1 if not specified).
6+
Creates a tag like v6.0.19-test1 and pushes it to origin.
7+
"""
8+
9+
import re
10+
import subprocess
11+
import sys
12+
import os
13+
14+
15+
def get_current_version():
16+
"""Extract version from setup.py"""
17+
setup_py_path = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'setup.py')
18+
19+
with open(setup_py_path, 'r') as f:
20+
content = f.read()
21+
22+
# Look for version="X.Y.Z" pattern
23+
match = re.search(r'version\s*=\s*["\']([^"\']+)["\']', content)
24+
if not match:
25+
raise ValueError("Could not find version in setup.py")
26+
27+
return match.group(1)
28+
29+
30+
def get_existing_test_tags(version):
31+
"""Get existing test tags for this version"""
32+
try:
33+
result = subprocess.run(['git', 'tag', '-l', f'v{version}-test*'],
34+
capture_output=True, text=True, check=True)
35+
return result.stdout.strip().split('\n') if result.stdout.strip() else []
36+
except subprocess.CalledProcessError:
37+
return []
38+
39+
40+
def get_next_test_number(version):
41+
"""Find the next available test number"""
42+
existing_tags = get_existing_test_tags(version)
43+
44+
if not existing_tags:
45+
return 1
46+
47+
# Extract test numbers
48+
test_numbers = []
49+
for tag in existing_tags:
50+
match = re.search(rf'v{re.escape(version)}-test(\d+)', tag)
51+
if match:
52+
test_numbers.append(int(match.group(1)))
53+
54+
return max(test_numbers) + 1 if test_numbers else 1
55+
56+
57+
def create_and_push_tag(version, test_num):
58+
"""Create and push the tag"""
59+
tag = f"v{version}-test{test_num}"
60+
61+
print(f"Creating tag: {tag}")
62+
63+
try:
64+
# Create the tag
65+
subprocess.run(['git', 'tag', tag], check=True)
66+
print(f"? Created tag {tag}")
67+
68+
# Push the tag
69+
subprocess.run(['git', 'push', 'origin', tag], check=True)
70+
print(f"? Pushed tag {tag} to origin")
71+
72+
return tag
73+
74+
except subprocess.CalledProcessError as e:
75+
print(f"Error: {e}")
76+
sys.exit(1)
77+
78+
79+
def main():
80+
# Handle help request
81+
if len(sys.argv) > 1 and sys.argv[1] in ['--help', '-h', 'help']:
82+
print(__doc__)
83+
print("\nExamples:")
84+
print(" ./scripts/tag-and-push # Auto-increment test number")
85+
print(" ./scripts/tag-and-push 1 # Create v6.0.19-test1")
86+
print(" ./scripts/tag-and-push 5 # Create v6.0.19-test5")
87+
return
88+
89+
try:
90+
# Get current version from setup.py
91+
version = get_current_version()
92+
print(f"Current project version: {version}")
93+
94+
# Get test number from command line or auto-increment
95+
if len(sys.argv) > 1:
96+
try:
97+
test_num = int(sys.argv[1])
98+
except ValueError:
99+
print("Error: Test number must be an integer")
100+
sys.exit(1)
101+
else:
102+
test_num = get_next_test_number(version)
103+
print(f"Auto-selected test number: {test_num}")
104+
105+
# Create and push tag
106+
tag = create_and_push_tag(version, test_num)
107+
108+
print(f"\n? Successfully created and pushed {tag}")
109+
print("This will trigger TestPyPI publishing via GitHub Actions.")
110+
111+
except Exception as e:
112+
print(f"Error: {e}")
113+
sys.exit(1)
114+
115+
116+
if __name__ == "__main__":
117+
main()

‎setup.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ def read_readme():
145145
name="ftoolss",
146146
# Version 5 introduced fmpfit
147147
# Version 5.2 introduces xerror_scipy (different handling of bounded params)
148-
version="6.0.19",
148+
version="6.0.20",
149149
description="Small C extensions for local image filters (fmedian, fsigma)",
150150
long_description=read_readme(),
151151
long_description_content_type="text/markdown",

0 commit comments

Comments
 (0)