11#!/usr/bin/env python3
22"""
3- Simplified package bumping for Codebelt service updates (Option B) .
3+ Package bumping for Codebelt service updates.
44
5- Only updates packages published by the triggering source repo.
5+ Updates packages published by the triggering source repo to the specified version.
6+ Additionally fetches the latest stable version from NuGet for all other Codebelt-related
7+ packages and updates them as well.
68Does NOT update Microsoft.Extensions.*, BenchmarkDotNet, or other third-party packages.
7- Does NOT parse TFM conditions - only bumps Codebelt/Cuemon/Savvyio packages to the triggering version.
89
910Usage:
1011 TRIGGER_SOURCE=cuemon TRIGGER_VERSION=10.3.0 python3 bump-nuget.py
1112
1213Behavior:
1314- If TRIGGER_SOURCE is "cuemon" and TRIGGER_VERSION is "10.3.0":
14- - Cuemon.Core: 10.2.1 → 10.3.0
15- - Cuemon.Extensions.IO: 10.2.1 → 10.3.0
15+ - Cuemon.Core: 10.2.1 → 10.3.0 (triggered source, set to given version)
16+ - Cuemon.Extensions.IO: 10.2.1 → 10.3.0 (triggered source, set to given version)
17+ - Codebelt.Extensions.BenchmarkDotNet.*: 1.2.3 → <latest from NuGet> (other Codebelt)
1618 - Microsoft.Extensions.Hosting: 9.0.13 → UNCHANGED (not a Codebelt package)
1719 - BenchmarkDotNet: 0.15.8 → UNCHANGED (not a Codebelt package)
1820"""
1921
22+ import json
2023import re
2124import os
2225import sys
23- from typing import Dict , List
26+ import urllib .request
27+ from typing import Dict , List , Optional
2428
2529TRIGGER_SOURCE = os .environ .get ("TRIGGER_SOURCE" , "" )
2630TRIGGER_VERSION = os .environ .get ("TRIGGER_VERSION" , "" )
3135 "xunit" : ["Codebelt.Extensions.Xunit" ],
3236 "benchmarkdotnet" : ["Codebelt.Extensions.BenchmarkDotNet" ],
3337 "bootstrapper" : ["Codebelt.Bootstrapper" ],
38+ "carter" : ["Codebelt.Extensions.Carter" ],
3439 "newtonsoft-json" : [
3540 "Codebelt.Extensions.Newtonsoft.Json" ,
41+ "Codebelt.Extensions.AspNetCore.Newtonsoft.Json" ,
3642 "Codebelt.Extensions.AspNetCore.Mvc.Formatters.Newtonsoft" ,
3743 ],
3844 "aws-signature-v4" : ["Codebelt.Extensions.AspNetCore.Authentication.AwsSignature" ],
3945 "unitify" : ["Codebelt.Unitify" ],
4046 "yamldotnet" : [
4147 "Codebelt.Extensions.YamlDotNet" ,
48+ "Codebelt.Extensions.AspNetCore.Text.Yaml" ,
4249 "Codebelt.Extensions.AspNetCore.Mvc.Formatters.Text.Yaml" ,
4350 ],
4451 "globalization" : ["Codebelt.Extensions.Globalization" ],
4552 "asp-versioning" : ["Codebelt.Extensions.Asp.Versioning" ],
4653 "swashbuckle-aspnetcore" : ["Codebelt.Extensions.Swashbuckle" ],
4754 "savvyio" : ["Savvyio." ],
48- "shared-kernel" : [],
55+ "shared-kernel" : ["Codebelt.SharedKernel" ],
4956}
5057
5158
@@ -57,6 +64,38 @@ def is_triggered_package(package_name: str) -> bool:
5764 return any (package_name .startswith (prefix ) for prefix in prefixes )
5865
5966
67+ def is_codebelt_package (package_name : str ) -> bool :
68+ """Check if package belongs to any Codebelt repo (regardless of trigger source)."""
69+ for repo_prefixes in SOURCE_PACKAGE_MAP .values ():
70+ if any (package_name .startswith (prefix ) for prefix in repo_prefixes if prefix ):
71+ return True
72+ return False
73+
74+
75+ _nuget_version_cache : Dict [str , Optional [str ]] = {}
76+
77+
78+ def get_latest_nuget_version (package_name : str ) -> Optional [str ]:
79+ """Fetch the latest stable version of a package from NuGet."""
80+ if package_name in _nuget_version_cache :
81+ return _nuget_version_cache [package_name ]
82+
83+ url = f"https://api.nuget.org/v3-flatcontainer/{ package_name .lower ()} /index.json"
84+ try :
85+ with urllib .request .urlopen (url , timeout = 15 ) as response :
86+ data = json .loads (response .read ())
87+ versions = data .get ("versions" , [])
88+ # Stable versions have no hyphen (no pre-release suffix)
89+ stable = [v for v in versions if "-" not in v ]
90+ result = stable [- 1 ] if stable else (versions [- 1 ] if versions else None )
91+ except Exception as exc :
92+ print (f" Warning: Could not fetch latest version for { package_name } : { exc } " )
93+ result = None
94+
95+ _nuget_version_cache [package_name ] = result
96+ return result
97+
98+
6099def main ():
61100 if not TRIGGER_SOURCE or not TRIGGER_VERSION :
62101 print (
@@ -70,7 +109,7 @@ def main():
70109 target_version = TRIGGER_VERSION .lstrip ("v" )
71110
72111 print (f"Trigger: { TRIGGER_SOURCE } @ { target_version } " )
73- print (f"Only updating packages from: { TRIGGER_SOURCE } " )
112+ print (f"Triggered packages set to { target_version } ; other Codebelt packages fetched from NuGet. " )
74113 print ()
75114
76115 try :
@@ -87,16 +126,24 @@ def replace_version(m: re.Match) -> str:
87126 pkg = m .group (1 )
88127 current = m .group (2 )
89128
90- if not is_triggered_package (pkg ):
91- skipped_third_party .append (f" { pkg } (skipped - not from { TRIGGER_SOURCE } )" )
129+ if is_triggered_package (pkg ):
130+ if target_version != current :
131+ changes .append (f" { pkg } : { current } → { target_version } " )
132+ return m .group (0 ).replace (
133+ f'Version="{ current } "' , f'Version="{ target_version } "'
134+ )
92135 return m .group (0 )
93136
94- if target_version != current :
95- changes .append (f" { pkg } : { current } → { target_version } " )
96- return m .group (0 ).replace (
97- f'Version="{ current } "' , f'Version="{ target_version } "'
98- )
137+ if is_codebelt_package (pkg ):
138+ latest = get_latest_nuget_version (pkg )
139+ if latest and latest != current :
140+ changes .append (f" { pkg } : { current } → { latest } (latest from NuGet)" )
141+ return m .group (0 ).replace (
142+ f'Version="{ current } "' , f'Version="{ latest } "'
143+ )
144+ return m .group (0 )
99145
146+ skipped_third_party .append (f" { pkg } (skipped - not a Codebelt package)" )
100147 return m .group (0 )
101148
102149 # Match PackageVersion elements (handles multiline)
@@ -111,10 +158,10 @@ def replace_version(m: re.Match) -> str:
111158
112159 # Show results
113160 if changes :
114- print (f"Updated { len (changes )} package(s) from { TRIGGER_SOURCE } :" )
161+ print (f"Updated { len (changes )} package(s):" )
115162 print ("\n " .join (changes ))
116163 else :
117- print (f "No packages from { TRIGGER_SOURCE } needed updating." )
164+ print ("No Codebelt packages needed updating." )
118165
119166 if skipped_third_party :
120167 print ()
0 commit comments