3
3
import pathlib
4
4
import re
5
5
import sys
6
+ import urllib .request
7
+ import json
6
8
7
9
INIT_FILE = pathlib .Path ("socketsecurity/__init__.py" )
8
10
PYPROJECT_FILE = pathlib .Path ("pyproject.toml" )
9
11
10
12
VERSION_PATTERN = re .compile (r"__version__\s*=\s*['\"]([^'\"]+)['\"]" )
11
13
PYPROJECT_PATTERN = re .compile (r'^version\s*=\s*".*"$' , re .MULTILINE )
14
+ PYPI_API = "https://test.pypi.org/pypi/socketsecurity/json"
12
15
13
16
def read_version_from_init (path : pathlib .Path ) -> str :
14
17
content = path .read_text ()
@@ -28,12 +31,30 @@ def read_version_from_git(path: str) -> str:
28
31
except subprocess .CalledProcessError :
29
32
return None
30
33
31
- def bump_dev_version (version : str ) -> str :
34
+ def bump_patch_version (version : str ) -> str :
32
35
if ".dev" in version :
33
- base , dev = version .split (".dev" )
34
- return f"{ base } .dev{ int (dev )+ 1 } "
35
- else :
36
- return f"{ version } .dev1"
36
+ version = version .split (".dev" )[0 ]
37
+ parts = version .split ("." )
38
+ parts [- 1 ] = str (int (parts [- 1 ]) + 1 )
39
+ return "." .join (parts )
40
+
41
+ def fetch_existing_versions () -> set :
42
+ try :
43
+ with urllib .request .urlopen (PYPI_API ) as response :
44
+ data = json .load (response )
45
+ return set (data .get ("releases" , {}).keys ())
46
+ except Exception as e :
47
+ print (f"⚠️ Warning: Failed to fetch existing versions from Test PyPI: { e } " )
48
+ return set ()
49
+
50
+ def find_next_available_dev_version (base_version : str ) -> str :
51
+ existing_versions = fetch_existing_versions ()
52
+ for i in range (1 , 100 ):
53
+ candidate = f"{ base_version } .dev{ i } "
54
+ if candidate not in existing_versions :
55
+ return candidate
56
+ print ("❌ Could not find available .devN slot after 100 attempts." )
57
+ sys .exit (1 )
37
58
38
59
def inject_version (version : str ):
39
60
print (f"🔁 Updating version to: { version } " )
@@ -52,13 +73,18 @@ def inject_version(version: str):
52
73
PYPROJECT_FILE .write_text (new_pyproject )
53
74
54
75
def main ():
76
+ dev_mode = "--dev" in sys .argv
55
77
current_version = read_version_from_init (INIT_FILE )
56
78
previous_version = read_version_from_git ("socketsecurity/__init__.py" )
57
79
58
80
print (f"Current: { current_version } , Previous: { previous_version } " )
59
81
60
82
if current_version == previous_version :
61
- new_version = bump_dev_version (current_version )
83
+ if dev_mode :
84
+ base_version = current_version .split (".dev" )[0 ] if ".dev" in current_version else current_version
85
+ new_version = find_next_available_dev_version (base_version )
86
+ else :
87
+ new_version = bump_patch_version (current_version )
62
88
inject_version (new_version )
63
89
print ("⚠️ Version was unchanged — auto-bumped. Please git add + commit again." )
64
90
sys .exit (1 )
0 commit comments