Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update java version command with config file #886

Merged
merged 42 commits into from
Sep 28, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
6826c5f
Update java version command with config file
stefanTolksdorf Sep 27, 2023
8f4f41e
Merge branch 'main' into feature/java_version_upgrade
stefanTolksdorf Sep 27, 2023
9dc4472
Remove tests
stefanTolksdorf Sep 27, 2023
d59a7d0
Fix linting
stefanTolksdorf Sep 27, 2023
b09d9ca
Fix linting
stefanTolksdorf Sep 27, 2023
1f08ba3
Fix linting
stefanTolksdorf Sep 27, 2023
e1deeff
Fix linting
stefanTolksdorf Sep 27, 2023
6f58665
Fix linting
stefanTolksdorf Sep 27, 2023
e3c99ee
Fix linting
stefanTolksdorf Sep 27, 2023
d8add03
Add test for get_current_version
stefanTolksdorf Sep 27, 2023
946b49f
Add test for get_current_version
stefanTolksdorf Sep 27, 2023
17b14ba
Add test for get_current_version
stefanTolksdorf Sep 27, 2023
d67fd1c
Add test for get_current_version
stefanTolksdorf Sep 27, 2023
c73973b
Add test for get_current_version
stefanTolksdorf Sep 27, 2023
1840893
Add test for get_current_version
stefanTolksdorf Sep 27, 2023
b78a1e1
Add test for get_current_version
stefanTolksdorf Sep 27, 2023
1c484bd
Add test for get_current_version
stefanTolksdorf Sep 27, 2023
1493f5f
Add test for get_current_version
stefanTolksdorf Sep 27, 2023
22cee71
Add test for get_current_version
stefanTolksdorf Sep 27, 2023
20e6ac3
Add test for get_current_version
stefanTolksdorf Sep 27, 2023
59d29a5
Add test for get_current_version
stefanTolksdorf Sep 27, 2023
4b989c0
Add test for get_current_version
stefanTolksdorf Sep 27, 2023
2c0c63c
Add test for get_current_version
stefanTolksdorf Sep 27, 2023
7b65314
Add test for get_current_version
stefanTolksdorf Sep 27, 2023
cf453b6
Add test for get_current_version
stefanTolksdorf Sep 27, 2023
b52da66
Add test for get_current_version
stefanTolksdorf Sep 27, 2023
82920a0
Add test for get_current_version
stefanTolksdorf Sep 27, 2023
ab6c30c
Add test for get_current_version
stefanTolksdorf Sep 27, 2023
ea4162d
Add test for get_current_version
stefanTolksdorf Sep 27, 2023
24fa909
Add test for get_current_version
stefanTolksdorf Sep 27, 2023
288ed7c
Add test for get_current_version
stefanTolksdorf Sep 27, 2023
917c819
Add test for get_current_version
stefanTolksdorf Sep 27, 2023
51e75b5
Add test for get_current_version
stefanTolksdorf Sep 27, 2023
78e1c4c
Add test for get_current_version
stefanTolksdorf Sep 27, 2023
157d818
Add test for get_current_version
stefanTolksdorf Sep 27, 2023
c6ef840
Add test for get_current_version
stefanTolksdorf Sep 28, 2023
f3562d0
Add test for get_current_version
stefanTolksdorf Sep 28, 2023
10d2fb9
Add test for get_current_version
stefanTolksdorf Sep 28, 2023
188fd4a
Add test for get_current_version
stefanTolksdorf Sep 28, 2023
e949a16
Add test for get_current_version
stefanTolksdorf Sep 28, 2023
038f1f4
Add test for get_current_version
stefanTolksdorf Sep 28, 2023
830dfbe
Add test for get_current_version
stefanTolksdorf Sep 28, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
279 changes: 120 additions & 159 deletions pontos/version/commands/_java.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,199 +15,160 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.

import logging
import json
import re
from pathlib import Path
from typing import Literal, Optional, Union

from lxml import etree
from typing import Literal, Union, Dict, List, Any

from ._command import VersionCommand
from ..errors import VersionError
from ..schemes import PEP440VersioningScheme
from ..version import Version, VersionUpdate
from ._command import VersionCommand

TEMPLATE = """# pylint: disable=invalid-name

# THIS IS AN AUTOGENERATED FILE. DO NOT TOUCH!

__version__ = "{}"\n"""

VERSION_PATTERN = (
r"([0-9]+\.[0-9]+\.[0-9]+(-?([ab]|rc|alpha|beta)[0-9]+(.dev[0-9]+)?)?)"
r"^(?P<pre>.*[^\d])"
r"(?P<version>\d+\.\d+\.\d+"
r"(-?([ab]|rc|alpha|beta)\d+(.dev\d+)?)?)"
r"(?P<post>.*$)"
)


def find_file(
filename: Path, search_path: str, search_glob: str
) -> Optional[Path]:
"""Find a file somewhere within an directory tree

Arg:
filename: The file to look up
search_path: The path to look for the file
search_glob: The glob search pattern

Returns:
The file as Path object, if existing
"""
search_path = Path(search_path).resolve()
for file_path in search_path.glob(search_glob):
if file_path.is_file() and file_path.name == filename.name:
return file_path
logging.warning("File %s not found in %s.", filename.name, search_path)
return None


def replace_string_in_file(
file_path: Path, pattern: str, replacement: str
) -> None:
# Read the content of the file
content = file_path.read_text(encoding="utf-8")

# Search for the pattern in the content
match = re.search(pattern, content)

# Replace the matched group (Group 1) with the replacement
if match:
# Write the updated content back to the file
file_path.write_text(
content.replace(match.group(1), replacement), encoding="utf-8"
)
else:
logging.warning(
"Couldn't match the pattern %s in the content of %s.",
pattern,
file_path,
)
logging.warning("Content: %s", content)


# This class is used for Java Version command(s)
class JavaVersionCommand(VersionCommand):
project_file_name = "pom.xml"
_properties_file_path = Path("src/main/resources/application.properties")
_pom_xml: Optional[etree.Element] = None

def _get_version_from_pom_xml(self) -> Version:
"""
Return the version information from the <version> tag of the
pom.xml file. The version may be in non standardized form.
"""

pom_xml: etree.Element = self.pom_xml

version_element = pom_xml.find("{*}version")
if version_element is None:
raise VersionError("Version tag missing in pom.xml")

return PEP440VersioningScheme.parse_version(version_element.text)

def _update_pom_version(
self,
new_version: Version,
) -> None:
"""
Update the version in the pom.xml file
"""
pom_xml: etree.Element = self.pom_xml

version_element = pom_xml.find("{*}version")
if version_element is None:
raise VersionError("Version tag missing in pom.xml")
version_element.text = str(new_version)

etree.ElementTree(pom_xml).write(
self.project_file_path, pretty_print=True, encoding="utf-8"
)
project_file_name = "upgradeVersion.json"

def _update_properties_file(
self,
new_version: Version,
) -> None:
# update the java properties file version
if not self._properties_file_path.exists():
# skip if not existing
return
pattern = rf"sentry\.release={VERSION_PATTERN}"
replace_string_in_file(
self._properties_file_path,
pattern=pattern,
replacement=str(new_version),
)

def _update_swagger_config(
self,
new_version: Version,
) -> None:
# update swagger config file version
swagger_config_file = find_file(
filename=Path("SwaggerConfig.java"),
search_path="src",
search_glob="**/config/swagger/*",
)
if not swagger_config_file:
# skip if not existing
return
pattern = rf'\.version\("{VERSION_PATTERN}"\)'
replace_string_in_file(
swagger_config_file, pattern=pattern, replacement=str(new_version)
)

@property
def pom_xml(self) -> etree.Element:
if self._pom_xml is not None:
return self._pom_xml

if not self.project_file_path.exists():
raise VersionError("pom.xml file not found.")

try:
pom_xml: etree.ElementTree = etree.parse(self.project_file_path)
except etree.XMLSyntaxError as e:
raise VersionError(e) from e
def get_current_version(self) -> Version:
file_versions = self._read_versions_from_files()

self._pom_xml = pom_xml.getroot()
last_version = self._verify_version(file_versions)

return self._pom_xml
if last_version == "":
raise VersionError("no version found")

def get_current_version(self) -> Version:
"""Get the current version of this project
In go the version is only defined within the repository
tags, thus we need to check git, what tag is the latest"""
return self._get_version_from_pom_xml()
return self.versioning_scheme.parse_version(last_version)

def verify_version(
self, version: Union[Literal["current"], Version, None]
) -> None:
"""Verify the current version of this project"""
current_version = self.get_current_version()
file_versions = self._read_versions_from_files()

last_version = self._verify_version(file_versions)

if current_version != version:
if last_version != str(version):
raise VersionError(
f"Provided version {version} does not match the "
f"current version {current_version} in "
f"{self.project_file_path}."
f"current version {last_version} "
f"in '{self.project_file_path}'"
)

def update_version(
self, new_version: Version, *, force: bool = False
) -> VersionUpdate:
try:
package_version = self.get_current_version()
if not force and new_version == package_version:
return VersionUpdate(previous=package_version, new=new_version)
current_version = self.get_current_version()
if not force and new_version == current_version:
return VersionUpdate(previous=current_version, new=new_version)
except VersionError:
# just ignore current version and override it
package_version = None
current_version = None

changed_files = [self.project_file_path]
self._update_pom_version(new_version=new_version)
self._update_properties_file(new_version=new_version)
self._update_swagger_config(new_version=new_version)
changed_files = self._update_version_files(new_version)

return VersionUpdate(
previous=package_version,
previous=current_version,
new=new_version,
changed_files=changed_files,
)

def _update_version_files(self, new_version) -> List[Path]:
config = self._load_config()

changed_files: List[Path] = []
for file_config in config["files"]:
file_path = file_config["path"]
with (Path.cwd() / file_path).open("r") as input_file_handle:
stefanTolksdorf marked this conversation as resolved.
Show resolved Hide resolved
lines = input_file_handle.readlines()
line_number = file_config["line"]
version_line = lines[line_number - 1]

matches = re.match(VERSION_PATTERN, version_line, re.DOTALL)
if matches is None:
raise VersionError(
f"Line has no version, "
f"file:'{file_path}' "
f"lineNo:{line_number} "
f"content:'{version_line}'"
)
lines[line_number - 1] = (
matches.group("pre")
+ str(new_version)
+ matches.group("post")
)

content = "".join(lines)
with (Path.cwd() / file_path).open("w") as output_file_handle:
stefanTolksdorf marked this conversation as resolved.
Show resolved Hide resolved
output_file_handle.write(content)
changed_files.append(Path(file_config["path"]))
return changed_files

def _load_config(self) -> Dict[str, Any]:
version_config_file = Path.cwd() / "upgradeVersion.json"
if not version_config_file.exists():
raise VersionError(
f"No {version_config_file} config file found. "
"This file is required for pontos"
)

with version_config_file.open("r") as f:
json_string = f.read()
config = json.loads(json_string)
return config

def _read_versions_from_files(self) -> Dict[str, str]:
config = self._load_config()

file_versions = {}
for file_config in config["files"]:
file_path = file_config["path"]
file = Path.cwd() / file_path
if not file.exists():
raise VersionError(f"No {file} file found.")

Check warning on line 134 in pontos/version/commands/_java.py

View check run for this annotation

Codecov / codecov/patch

pontos/version/commands/_java.py#L134

Added line #L134 was not covered by tests

with file.open("r") as f:
line_number = file_config["line"]
readlines = f.readlines()
if line_number - 1 > len(readlines):
raise VersionError(

Check warning on line 140 in pontos/version/commands/_java.py

View check run for this annotation

Codecov / codecov/patch

pontos/version/commands/_java.py#L140

Added line #L140 was not covered by tests
f"Line number:{line_number} "
f"is beyond file lines:{len(readlines) + 1} "
f"file:'{file_path}'"
)
version_line = readlines[line_number - 1]
matches = re.match(VERSION_PATTERN, version_line, re.DOTALL)
if matches is None:
raise VersionError(
f"Line has no version, "
f"file:'{file_path}' "
f"lineNo:{line_number} "
f"content:'{version_line}'"
)
file_versions[file_path] = matches.group("version")
return file_versions

def _verify_version(self, file_versions: Dict[str, str]) -> str:
last_version = ""
last_file_name = ""
for file_name, version in file_versions.items():
if last_version == "":
last_version = version
last_file_name = file_name
continue

if last_version != version:
raise VersionError(

Check warning on line 167 in pontos/version/commands/_java.py

View check run for this annotation

Codecov / codecov/patch

pontos/version/commands/_java.py#L167

Added line #L167 was not covered by tests
f"Versions are not the same "
f"last_file_name:'{last_file_name}' "
f"last_version:'{last_version}' "
f"file_name:'{file_name}' "
f"version:'{version}'"
)
return last_version
Loading