|
5 | 5 |
|
6 | 6 | import copy |
7 | 7 | import logging |
| 8 | +import re |
8 | 9 | from datetime import datetime, timezone |
9 | | -from typing import Type |
| 10 | +from typing import Tuple, Type |
10 | 11 |
|
| 12 | +from packaging.specifiers import SpecifierSet |
11 | 13 | from packaging.version import Version |
12 | 14 |
|
13 | 15 | from airbyte_cdk.manifest_migrations.exceptions import ( |
|
25 | 27 | METADATA_TAG = "metadata" |
26 | 28 | MANIFEST_VERSION_TAG = "version" |
27 | 29 | APPLIED_MIGRATIONS_TAG = "applied_migrations" |
28 | | - |
| 30 | +WILDCARD_VERSION_PATTERN = ".*" |
29 | 31 | LOGGER = logging.getLogger("airbyte.cdk.manifest_migrations") |
30 | 32 |
|
31 | 33 |
|
@@ -77,11 +79,14 @@ def _handle_migration( |
77 | 79 | """ |
78 | 80 | try: |
79 | 81 | migration_instance = migration_class() |
80 | | - if self._version_is_valid_for_migration(manifest_version, migration_version): |
| 82 | + can_apply_migration, should_bump_version = self._version_is_valid_for_migration( |
| 83 | + manifest_version, migration_version |
| 84 | + ) |
| 85 | + if can_apply_migration: |
81 | 86 | migration_instance._process_manifest(self._migrated_manifest) |
82 | 87 | if migration_instance.is_migrated: |
83 | | - # set the updated manifest version, after migration has been applied |
84 | | - self._set_manifest_version(migration_version) |
| 88 | + if should_bump_version: |
| 89 | + self._set_manifest_version(migration_version) |
85 | 90 | self._set_migration_trace(migration_class, manifest_version, migration_version) |
86 | 91 | else: |
87 | 92 | LOGGER.info( |
@@ -112,18 +117,30 @@ def _version_is_valid_for_migration( |
112 | 117 | self, |
113 | 118 | manifest_version: str, |
114 | 119 | migration_version: str, |
115 | | - ) -> bool: |
| 120 | + ) -> Tuple[bool, bool]: |
| 121 | + """ |
| 122 | + Decide whether *manifest_version* satisfies the *migration_version* rule. |
| 123 | +
|
| 124 | + Rules |
| 125 | + ----- |
| 126 | + 1. ``"*"`` |
| 127 | + – Wildcard: anything matches. |
| 128 | + 2. String starts with a PEP 440 operator (``==``, ``!=``, ``<=``, ``>=``, |
| 129 | + ``<``, ``>``, ``~=``, etc.) |
| 130 | + – Treat *migration_version* as a SpecifierSet and test the manifest |
| 131 | + version against it. |
| 132 | + 3. Plain version |
| 133 | + – Interpret both strings as concrete versions and return |
| 134 | + ``manifest_version <= migration_version``. |
116 | 135 | """ |
117 | | - Checks if the given manifest version is less than or equal to the specified migration version. |
| 136 | + if re.match(WILDCARD_VERSION_PATTERN, migration_version): |
| 137 | + return True, False |
118 | 138 |
|
119 | | - Args: |
120 | | - manifest_version (str): The version of the manifest to check. |
121 | | - migration_version (str): The migration version to compare against. |
| 139 | + if migration_version.startswith(("=", "!", ">", "<", "~")): |
| 140 | + spec = SpecifierSet(migration_version) |
| 141 | + return spec.contains(Version(manifest_version)), False |
122 | 142 |
|
123 | | - Returns: |
124 | | - bool: True if the manifest version is less than or equal to the migration version, False otherwise. |
125 | | - """ |
126 | | - return Version(manifest_version) <= Version(migration_version) |
| 143 | + return Version(manifest_version) <= Version(migration_version), True |
127 | 144 |
|
128 | 145 | def _set_manifest_version(self, version: str) -> None: |
129 | 146 | """ |
|
0 commit comments