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 ("\n Examples:" )
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 ()
0 commit comments