66if you're testing locally.
77"""
88
9- import itertools
109import logging
1110import re
12- import shutil
1311from pathlib import Path
14- from typing import Any as _Any
15- from typing import Iterable
1612
1713import bost .operations
18- from bost import main as bost_main
19- from bost .operations import update_references as bost_update_references
20- from bost .pull import OWNER , REPO , SchemaMetadata , get_source_repo
14+ from bost .pull import OWNER , REPO
2115
22- from . import change_schemas , diff , loader , matrix
16+ from . import diff , loader , matrix , versioning
2317
24- BO4E_BASE_DIR = Path (__file__ ).parents [2 ] / "tmp/bo4e_json_schemas"
25- LOCAL_JSON_SCHEMA_DIR = Path (__file__ ).parents [2 ] / "json_schemas"
2618logger = logging .getLogger (__name__ )
2719
28-
29- def pull_bo4e_version (version : str , output : Path , gh_token : str | None = None ) -> None :
30- """
31- Pull the BO4E version from the given version string.
32- """
33- bost_main (
34- output = output ,
35- target_version = version ,
36- update_refs = True ,
37- set_default_version = False ,
38- clear_output = True ,
39- token = gh_token ,
40- )
41-
42-
43- def update_references (path : Path , version : str ) -> None :
44- """
45- Update the references in the given path. This step is needed for the local build.
46- """
47- schema_namespace = {}
48- for schema_path in loader .get_namespace (path ):
49- local_path = Path (path , * schema_path ).with_suffix (".json" )
50- schema_namespace [schema_path [- 1 ]] = SchemaMetadata (
51- class_name = schema_path [- 1 ],
52- download_url = "" ,
53- module_path = schema_path ,
54- file_path = local_path ,
55- cached_path = local_path ,
56- token = None ,
57- )
58- for schema_metadata in schema_namespace .values ():
59- bost_update_references (schema_metadata , schema_namespace , version )
60- schema_metadata .save ()
61-
62-
63- def pull_or_reuse_bo4e_version (version : str , gh_token : str | None = None , from_local : bool = False ) -> Path :
64- """
65- Pull the BO4E version from the given version string or reuse the version if it was already pulled before.
66- If version is None use the BO4E version of the checkout working directory by assuming the compiled json
67- schemas in /json_schemas.
68- Returns the path of the bo4e directory.
69- """
70- bo4e_dir = BO4E_BASE_DIR / version
71-
72- if from_local :
73- if not any (LOCAL_JSON_SCHEMA_DIR .rglob ("*.json" )):
74- raise ValueError (
75- "No local json schemas found in /json_schemas. "
76- "Please ensure that the json schemas are build on beforehand."
77- )
78- if bo4e_dir .exists ():
79- shutil .rmtree (bo4e_dir )
80- shutil .copytree (LOCAL_JSON_SCHEMA_DIR , bo4e_dir )
81- update_references (bo4e_dir , version )
82- elif any (bo4e_dir .rglob ("*.json" )):
83- return bo4e_dir
84- else :
85- pull_bo4e_version (version , bo4e_dir , gh_token )
86- return bo4e_dir
87-
88-
89- def compare_bo4e_versions (
90- version_old : str , version_new : str , gh_token : str | None = None , from_local : bool = False
91- ) -> Iterable [change_schemas .Change ]:
92- """
93- Compare the old version with the new version.
94- If version_new is None use the BO4E version of the checkout working directory by assuming the compiled json
95- schemas in /json_schemas.
96- """
97- dir_old_schemas = pull_or_reuse_bo4e_version (version_old , gh_token )
98- dir_new_schemas = pull_or_reuse_bo4e_version (version_new , gh_token , from_local = from_local )
99- print (f"Comparing { version_old } with { version_new } " )
100- yield from diff .diff_schemas (dir_old_schemas , dir_new_schemas )
101-
102-
103- def compare_bo4e_versions_iteratively (
104- versions : Iterable [str ], cur_version : str | None = None , gh_token : str | None = None
105- ) -> dict [tuple [str , str ], Iterable [change_schemas .Change ]]:
106- """
107- Compare the versions iteratively. Each version at index i will be compared to the version at index i+1.
108- Additionally, if cur_version is provided, the last version in the list will be compared to the version
109- in the checkout working directory. The value of cur_version will be used to set the key in the returned
110- dict.
111- Note:
112- - versions must contain at least one element.
113- - versions should be sorted in ascending order.
114- - if using cur_version, ensure that the json schemas of the checkout working directory
115- were build on beforehand. They should be located in /json_schemas.
116- """
117- print (f"Comparing versions { versions } with cur_version { cur_version } " )
118- changes = {}
119- last_version : str = "" # This value is never used but makes mypy and pylint happy
120- for version_old , version_new in itertools .pairwise (versions ):
121- last_version = version_new
122- changes [version_old , version_new ] = compare_bo4e_versions (version_old , version_new , gh_token )
123- if cur_version is not None :
124- changes [last_version , cur_version ] = compare_bo4e_versions (last_version , cur_version , gh_token , from_local = True )
125- print ("Comparisons finished." )
126- return changes
127-
128-
12920REGEX_RELEASE_VERSION = re .compile (r"^v(\d{6}\.\d+\.\d+)$" )
13021REGEX_RELEASE_CANDIDATE_VERSION = re .compile (r"^v(\d{6}\.\d+\.\d+)-rc\d+$" )
13122
13223
133- def get_last_n_release_versions (n : int , include_rc : bool = False , gh_token : str | None = None ) -> Iterable [str ]:
134- """
135- Get the last n release versions from the BO4E repository.
136- """
137- repo = get_source_repo (gh_token )
138- releases = repo .get_releases ()
139- counter = 0
140-
141- for release in releases :
142- if not REGEX_RELEASE_VERSION .fullmatch (release .tag_name ) and (
143- not include_rc or not REGEX_RELEASE_CANDIDATE_VERSION .fullmatch (release .tag_name )
144- ):
145- continue
146- counter += 1
147- yield release .tag_name
148- if counter >= n :
149- return
150-
151- logger .warning ("Only %d matching releases found. Returning all releases." , counter )
152-
153-
154- def get_all_release_versions_since_20240100 (include_rc : bool = False , gh_token : str | None = None ) -> Iterable [str ]:
155- """
156- Get all release versions since v202401.0.0 from the BO4E repository.
157- """
158- repo = get_source_repo (gh_token )
159- releases = repo .get_releases ()
160- version_threshold = "v202401.0.0"
161-
162- for release in releases :
163- if not REGEX_RELEASE_VERSION .fullmatch (release .tag_name ) and (
164- not include_rc or not REGEX_RELEASE_CANDIDATE_VERSION .fullmatch (release .tag_name )
165- ):
166- continue
167- yield release .tag_name
168- if release .tag_name == version_threshold :
169- return
170-
171- logger .warning ("Threshold version %s not found. Returned all matching releases." , version_threshold )
172-
173-
17424def _monkey_patch_bost_regex_if_local_testing (version : str ) -> None :
17525 regex_expected_version = re .compile (r"^v\d+\.\d+\.\d+(?:-rc\d+)?$" )
17626 if not regex_expected_version .fullmatch (version ):
@@ -196,20 +46,20 @@ def create_tables_for_doc(
19646 The compatibility matrix will be built for last_n_versions + the current version in the checkout working directory.
19747 If you set last_n_versions = 0 all versions since v202401.0.0 will be compared.
19848 Note: The matrix will never contain the first version as column. Each column is a comparison to the version before.
199- Note: Release candidates are excluded.
49+ Note: Only functional releases will be compared since technical releases are enforced to be fully compatible.
50+ See https://github.com/bo4e/BO4E-python/issues/784
20051 """
20152 _monkey_patch_bost_regex_if_local_testing (gh_version )
20253 logger .info ("Retrieving the last %d release versions" , last_n_versions )
203- if last_n_versions > 0 :
204- versions = list (reversed (list (get_last_n_release_versions (last_n_versions , gh_token = gh_token ))))
205- else :
206- versions = list (reversed (list (get_all_release_versions_since_20240100 (gh_token = gh_token ))))
54+ versions = list (
55+ reversed (list (versioning .get_last_n_tags (last_n_versions , ref = gh_version , exclude_technical_bumps = True )))
56+ )
20757 logger .info ("Comparing versions iteratively: %s" , " -> " .join ([* versions , gh_version ]))
208- changes_iterables = compare_bo4e_versions_iteratively (versions , gh_version , gh_token = gh_token )
58+ changes_iterables = diff . compare_bo4e_versions_iteratively (versions , gh_version , gh_token = gh_token )
20959 logger .info ("Building namespaces" )
21060 changes = {key : list (value ) for key , value in changes_iterables .items ()}
211- namespaces = {version : list (loader .get_namespace (BO4E_BASE_DIR / version )) for version in versions }
212- namespaces [gh_version ] = list (loader .get_namespace (BO4E_BASE_DIR / gh_version ))
61+ namespaces = {version : list (loader .get_namespace (loader . BO4E_BASE_DIR / version )) for version in versions }
62+ namespaces [gh_version ] = list (loader .get_namespace (loader . BO4E_BASE_DIR / gh_version ))
21363 logger .info ("Creating compatibility matrix" )
21464 matrix .create_compatibility_matrix_csv (
21565 compatibility_matrix_output_file , [* versions , gh_version ], namespaces , changes
@@ -224,5 +74,5 @@ def test_create_tables_for_doc() -> None:
22474 create_tables_for_doc (
22575 Path (__file__ ).parents [1 ] / "compatibility_matrix.csv" ,
22676 "local" ,
227- last_n_versions = 3 ,
77+ last_n_versions = 0 ,
22878 )
0 commit comments