2121FLAG_COMPARE_EXACT_VERSION = False
2222
2323
24- def compare_versions (v1 : str , v2 : str ) -> int :
24+ def compare_versions (orig_v1 : str , orig_v2 : str , major_only : bool ) -> int :
2525 """Compare two versions, return 1 if v1 > v2, 0 if v1 == v2, -1 if v1 < v2"""
26- if v1 .startswith ("v" ):
27- v1 = v1 [1 :]
28- if v2 .startswith ("v" ):
29- v2 = v2 [1 :]
30- v1 = v1 .split ("." )
31- v2 = v2 .split ("." )
26+ if orig_v1 .startswith ("v" ):
27+ orig_v1 = orig_v1 [1 :]
28+ if orig_v2 .startswith ("v" ):
29+ orig_v2 = orig_v2 [1 :]
30+ v1 = orig_v1 .split ("." )
31+ v2 = orig_v2 .split ("." )
32+ if major_only :
33+ v1 = [v1 [0 ]]
34+ v2 = [v2 [0 ]]
3235 try :
3336 compare_count = max (len (v1 ), len (v2 )) if FLAG_COMPARE_EXACT_VERSION else 1
3437 for i in range (compare_count ):
@@ -39,10 +42,16 @@ def compare_versions(v1: str, v2: str) -> int:
3942 if v1_i < v2_i :
4043 return - 1
4144 except ValueError :
42- logging .warning (f"Could not compare versions { v1 } and { v2 } " )
45+ logging .warning (f"Could not compare versions { orig_v1 } and { orig_v2 } " )
4346 return 0
4447
4548
49+ def _fix_version (tag_name : str , major_only : bool ) -> str :
50+ if major_only :
51+ return tag_name .split ("." )[0 ]
52+ return tag_name
53+
54+
4655class GithubActionsTools (object ):
4756 _wf_cache : dict [str , dict [str , Any ]] = dict () # repo_name -> [path -> workflow/yaml]
4857 actions_latest_release : dict [str , str ] = dict () # action_name@current_release -> latest_release_tag
@@ -70,7 +79,7 @@ def get_workflow_actions(self, repo_name: str, workflow_path: str) -> Set[str]:
7079 res .add (step ["uses" ])
7180 return res
7281
73- def check_for_updates (self , action_name : str ) -> Optional [str ]:
82+ def check_for_updates (self , action_name : str , major_only : bool ) -> Optional [str ]:
7483 """Check whether an action has an update, and return the latest version if it does syntax for uses:
7584 https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_iduses
7685 """
@@ -81,19 +90,19 @@ def check_for_updates(self, action_name: str) -> Optional[str]:
8190 if repo_name in self .actions_latest_release :
8291 latest_release = self .actions_latest_release [repo_name ]
8392 logging .debug (f"Found in cache { repo_name } : { latest_release } " )
84- return latest_release if compare_versions (latest_release , current_version ) else None
93+ return latest_release if compare_versions (latest_release , current_version , major_only ) else None
8594 repo = self .client .get_repo (repo_name )
8695 logging .debug (f"Getting latest release for repository: { repo_name } " )
8796 try :
8897 latest_release = repo .get_latest_release ()
89- if compare_versions (latest_release .tag_name , current_version ):
90- self .actions_latest_release [repo_name ] = latest_release .tag_name
98+ if compare_versions (latest_release .tag_name , current_version , major_only ):
99+ self .actions_latest_release [repo_name ] = _fix_version ( latest_release .tag_name , major_only )
91100 return latest_release .tag_name
92101 except UnknownObjectException :
93102 logging .warning (f"No releases found for repository: { repo_name } " )
94103 return None
95104
96- def get_repo_actions_latest (self , repo_name : str ) -> Dict [str , List [ActionVersion ]]:
105+ def get_repo_actions_latest (self , repo_name : str , major_only : bool ) -> Dict [str , List [ActionVersion ]]:
97106 workflow_paths = self ._get_github_workflow_filenames (repo_name )
98107 res = dict ()
99108 for path in workflow_paths :
@@ -104,7 +113,7 @@ def get_repo_actions_latest(self, repo_name: str) -> Dict[str, List[ActionVersio
104113 continue
105114 action_name , curr_version = action .split ("@" )
106115 if action not in self .actions_latest_release :
107- latest = self .check_for_updates (action )
116+ latest = self .check_for_updates (action , major_only )
108117 self .actions_latest_release [action ] = latest
109118 else :
110119 latest = self .actions_latest_release [action ]
@@ -124,11 +133,11 @@ def get_repo_workflow_names(self, repo_name: str) -> Dict[str, str]:
124133 return res
125134
126135 def update_actions (
127- self ,
128- repo_name : str ,
129- workflow_path : str ,
130- updates : List [ActionVersion ],
131- commit_msg : str ,
136+ self ,
137+ repo_name : str ,
138+ workflow_path : str ,
139+ updates : List [ActionVersion ],
140+ commit_msg : str ,
132141 ) -> None :
133142 workflow_content = self ._get_workflow_file_content (repo_name , workflow_path )
134143 if isinstance (workflow_content , bytes ):
@@ -263,11 +272,18 @@ def cli(ctx, verbose: int, repo: str, github_token: Optional[str], compare_exact
263272 show_default = True ,
264273 help = "Commit msg, only relevant when remote repo" ,
265274)
275+ @click .option (
276+ "-m" ,
277+ "--major-only" ,
278+ is_flag = True ,
279+ default = False ,
280+ help = "Compare major versions only, e.g., v1.2.3 will not be upgraded to v1.2.4 but to v2" ,
281+ )
266282@click .pass_context
267- def update_actions (ctx , update : bool , commit_msg : str ) :
283+ def update_actions (ctx , update : bool , commit_msg : str , major_only : bool ) -> None :
268284 gh , repo = ctx .obj ["gh" ], ctx .obj ["repo" ]
269285 workflow_names = gh .get_repo_workflow_names (repo )
270- workflow_action_versions = gh .get_repo_actions_latest (repo )
286+ workflow_action_versions = gh .get_repo_actions_latest (repo , major_only )
271287 max_action_name_length , max_version_length = 0 , 0
272288 for workflow_path , actions in workflow_action_versions .items ():
273289 for action in workflow_action_versions [workflow_path ]:
0 commit comments