Commit f1f90ed5 authored by Laurent Peuch's avatar Laurent Peuch
Browse files

feat: add a set_cubes_cw_max_version script for cubes

parent 830225b6f712
Pipeline #82424 failed with stage
in 39 seconds
......@@ -22,6 +22,7 @@ from cube_doctor.transforms.run_script import RunScript
from cube_doctor.transforms.run_script_no_mr import RunScriptNoMr
from cube_doctor.transforms.regenerate_gitlab_ci import RegenerateGitlabCI
from cube_doctor.transforms.rebase_all import RebaseAllMyMRs
from cube_doctor.transforms.set_cubes_cw_max_version import SetCubeCubicWebMaxVersion
def hg_command(dir, command):
......@@ -93,6 +94,7 @@ commands = {
"replace-set-attributes": ReplaceSetAttributesWithSetCW().workflow,
"update-licence-dates": UpdateCubeLicenceDates().workflow,
"auto-upgrade-dependencies": AutoUpgradeDependencies().workflow,
"set-cubes-cw-max-version": SetCubeCubicWebMaxVersion().workflow,
"regenerate-gitlab-ci": RegenerateGitlabCI().workflow,
"run-script": RunScript().workflow,
"run-script-no-mr": RunScriptNoMr().workflow,
......
import re
import string
import requests
import operator
from cube_doctor import Command
from distutils.version import LooseVersion
from redbaron import RedBaron
STRING_TO_OPERATOR = {
"==": operator.eq,
"<": operator.lt,
"<=": operator.le,
"!=": operator.ne,
">=": operator.ge,
">": operator.gt,
}
OPERATOR_TO_STRING = {y: x for x, y in STRING_TO_OPERATOR.items()}
class SetCubeCubicWebMaxVersion(Command):
BRANCH_NAME = "topic/default/set_cubes_cw_max_version"
commit_message = "feat(setup.py): increase cubicweb max version to %s"
AUTO_MR_AUTO_MERGE = True
TARGETS = ("cubes",)
def pre_check(self, root_files):
if "__pkginfo__.py" in root_files:
return
cube_dir = [x for x in root_files if x.startswith("cubicweb_")]
if not cube_dir:
return "continue"
def modify_code(self, cube, repo, root_files, branches, other_args):
cube_dir = [x for x in root_files if x.startswith("cubicweb_")]
if (repo.path / "__pkginfo__.py").exists():
pkginfo_path = repo.path / "__pkginfo__.py"
elif cube_dir and (repo.path / cube_dir[0] / "__pkginfo__.py").exists():
pkginfo_path = repo.path / cube_dir[0] / "__pkginfo__.py"
else:
return
depends, red, red_depends = self.parse_pkginfo(repo.read_file(pkginfo_path))
if "cubicweb" not in depends:
return
depends = {"cubicweb": depends["cubicweb"]}
depends = self.merge_depends_with_pypi_info(depends)
dependency = "cubicweb"
conditions = self.parse_conditions(
depends["cubicweb"]["current_version_scheme"]
)
depends["cubicweb"]["all_versions"] = [
version
for version in depends["cubicweb"]["all_versions"]
if not set(string.ascii_letters).intersection(version["version"])
]
compatible_versions = depends["cubicweb"]["all_versions"]
maximum_version = LooseVersion(
sorted(compatible_versions, key=lambda x: LooseVersion(x["version"]))[-1][
"version"
]
)
upper_range = ".".join(
map(str, [maximum_version.version[0], maximum_version.version[1] + 1, 0])
)
new_conditions = []
for condition_operator, condition_value in conditions:
if condition_operator in (operator.gt, operator.ge):
new_conditions.append([condition_operator, condition_value])
break
# progressive upgrade
for condition_operator, condition_value in conditions:
condition_second_number = LooseVersion(condition_value).version[1]
if condition_operator == operator.lt and condition_second_number in (
31,
32,
33,
34,
):
parsed_condition = f"3.{condition_second_number + 1}.0"
if upper_range < parsed_condition:
new_conditions.append([operator.lt, upper_range])
else:
new_conditions.append([operator.lt, parsed_condition])
break
else:
min_middle_version = None
if new_conditions:
new_condition_operator, new_condition_value = new_conditions[0]
min_middle_version = LooseVersion(new_condition_value)
if min_middle_version and min_middle_version.version[1] > 31:
new_conditions.append(
[operator.lt, f"3.{min_middle_version.version[1] + 1}.0"]
)
else:
new_conditions.append([operator.lt, "3.32.0"])
# for dependency, value in depends.items():
entry = red_depends.value.filter(
lambda x: hasattr(x, "key") and x.key.to_python() == dependency
)[0]
update_as_str = ", ".join(
[f"{OPERATOR_TO_STRING[x]} {y}" for x, y in new_conditions]
)
entry.value = '"' + update_as_str + '"'
repo.write_file(pkginfo_path, red.dumps())
yield {
"branch_name": self.BRANCH_NAME,
"commit_message": (
self.commit_message
% f"{maximum_version.version[0]}.{maximum_version.version[1]}.x"
),
}
def parse_pkginfo(self, pkginfo_content):
red = RedBaron(pkginfo_content)
depends = red.find("assign", lambda x: x.target.value == "__depends__")
if not depends:
raise Exception("I couldn't find __depends__ in the __pkginfo__.py")
assert depends.value.type == "dict"
# XXX use to_python() somehow
return eval(depends.value.dumps()), red, depends
def merge_depends_with_pypi_info(self, depends):
new_depends = {}
for key, value in depends.items():
pkg_name = key.split("[", 1)[0]
print("Get all releases of %s..." % pkg_name)
response = requests.get(
"https://pypi.org/pypi/%s/json" % pkg_name, timeout=30
)
if response.status_code == 404:
print("Warning: %s doesn't exist on pypi, skip it" % pkg_name)
continue
data = response.json()
all_versions = []
for key2, value2 in data["releases"].items():
# sometime we don't have metadata information for a release :|
all_versions.append(value2[0] if value2 else {})
all_versions[-1]["version"] = key2
new_depends[key] = {
"pkg_name": pkg_name,
"current_version_scheme": value,
"all_versions": all_versions,
}
return new_depends
def parse_conditions(self, conditions):
parsed_conditions = []
if not conditions:
return None
for i in conditions.split(","):
version_operator, version_number = re.match(
"(==|>=|<=|>|<|~=) *([0-9.]*)", i.strip()
).groups()
if version_operator == "~=":
parsed_conditions.append([operator.ge, version_number])
superior_version = LooseVersion(version_number).version
superior_version[1] += 1
superior_version = ".".join(str(x) for x in superior_version)
parsed_conditions.append([operator.lt, superior_version])
else:
parsed_conditions.append(
[
STRING_TO_OPERATOR[version_operator],
version_number,
]
)
return parsed_conditions
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment