Pour tout problème contactez-nous par mail : support@froggit.fr | La FAQ :grey_question: | Rejoignez-nous sur le Chat :speech_balloon:

Skip to content
Snippets Groups Projects
Commit 72f1d5c3 authored by Dorian Turba's avatar Dorian Turba
Browse files

style depandabot and compare.py

parent 37a1b86a
No related branches found
No related tags found
1 merge request!1feat: add depandabot template
......@@ -22,6 +22,8 @@ dependencies = [
[project.optional-dependencies]
QUALITY = [
"black",
"mypy",
"pre-commit",
]
......@@ -29,3 +31,10 @@ QUALITY = [
strict-config = true
plugins.line-length.enabled = false
[[tool.mypy.overrides]]
module = [
"packaging.requirements",
"packaging.specifiers",
"packaging",
]
ignore_missing_imports = true
\ No newline at end of file
......@@ -7,6 +7,11 @@ import argparse
import typing
class OldNewRequirements(typing.NamedTuple):
old: packaging.requirements.Requirement
new: packaging.requirements.Requirement
def clean_lines(f: io.TextIOWrapper) -> typing.Generator[str, None, None]:
for line in f:
# remove comments and hashes
......@@ -16,71 +21,16 @@ def clean_lines(f: io.TextIOWrapper) -> typing.Generator[str, None, None]:
yield line.rstrip("\n").rstrip("\\")
def compare_requirements(
file: pathlib.Path,
) -> tuple[
packaging.requirements.Requirement,
packaging.requirements.Requirement,
packaging.requirements.Requirement,
]:
set_before = set()
set_after = set()
with file.open() as f:
set_after = {
packaging.requirements.Requirement(line) for line in clean_lines(f)
}
set_before = {
packaging.requirements.Requirement(line)
for line in clean_lines(retrieve_requirements(file))
}
d_new = {s.name: s for s in set_after.difference(set_before)}
d_old = {s.name: s for s in set_before.difference(set_after)}
set_added = {v for k, v in d_new.items() if k not in d_old}
set_updated = {(d_old[k], v) for k, v in d_new.items() if k in d_old}
set_removed = {v for k, v in d_old.items() if k not in d_new}
return (set_added, set_updated, set_removed)
def generate_changes(
added: set[packaging.requirements.Requirement],
updated: set[
tuple[
packaging.requirements.Requirement,
packaging.requirements.Requirement,
]
],
removed: set[packaging.requirements.Requirement],
) -> str:
description = []
for a in added:
description.append(
f"- Added `{a.name}` version "
f"`{retrieve_equal_version(a.specifier).version}`"
)
for u in updated:
description.append(
f"- Bump `{u[0].name}` from "
f"`{retrieve_equal_version(u[0].specifier).version}` to "
f"`{retrieve_equal_version(u[1].specifier).version}`"
)
for r in removed:
description.append(
f"- Removed `{r.name}` version "
f"`{retrieve_equal_version(r.specifier).version}`"
)
return "\r\n".join(description)
def retrieve_equal_version(
specifier: packaging.specifiers.SpecifierSet,
) -> packaging.specifiers.Specifier:
"""
:raises ValueError: if no equal version is found
"""
for s in specifier:
if s.operator == "==":
return s
raise ValueError("No equal version found")
def retrieve_requirements(file: pathlib.Path) -> io.StringIO:
......@@ -92,27 +42,107 @@ def retrieve_requirements(file: pathlib.Path) -> io.StringIO:
return content
def compare_requirements(
requirements: pathlib.Path,
) -> tuple[
set[packaging.requirements.Requirement],
set[
OldNewRequirements[
packaging.requirements.Requirement, packaging.requirements.Requirement
]
],
set[packaging.requirements.Requirement],
]:
with requirements.open() as file:
set_after = {
packaging.requirements.Requirement(line) for line in clean_lines(file)
}
set_before = {
packaging.requirements.Requirement(line)
for line in clean_lines(retrieve_requirements(requirements))
}
new_requirements = {
requirement.name: requirement
for requirement in set_after.difference(set_before)
}
old_requirements = {
requirement.name: requirement
for requirement in set_before.difference(set_after)
}
added_requirements = {
requirement
for package_name, requirement in new_requirements.items()
if package_name not in old_requirements
}
updated_requirements = {
OldNewRequirements(old_requirements[package_name], requirement)
for package_name, requirement in new_requirements.items()
if package_name in old_requirements
}
removed_requirements = {
requirement
for package_name, requirement in old_requirements.items()
if package_name not in new_requirements
}
return added_requirements, updated_requirements, removed_requirements
def parser() -> argparse.ArgumentParser:
p = argparse.ArgumentParser()
p.add_argument(
parser = argparse.ArgumentParser()
parser.add_argument(
"requirements_file",
nargs="?",
default=pathlib.Path("requirements.txt"),
type=pathlib.Path,
)
p.add_argument(
parser.add_argument(
"-o",
nargs=1,
nargs="?",
default=pathlib.Path("description.md"),
type=pathlib.Path,
required=False,
)
return p
return parser
def generate_changes(
added_requirements: set[packaging.requirements.Requirement],
updated: set[
OldNewRequirements[
packaging.requirements.Requirement,
packaging.requirements.Requirement,
]
],
removed: set[packaging.requirements.Requirement],
) -> str:
description = (
[
f"- Added `{requirement.name}` version "
f"`{retrieve_equal_version(requirement.specifier).version}`"
for requirement in added_requirements
]
+ [
f"- Bump `{requirements.old.name}` from "
f"`{retrieve_equal_version(requirements.old.specifier).version}` to "
f"`{retrieve_equal_version(requirements.new.specifier).version}`"
for requirements in updated
]
+ [
f"- Removed `{requirement.name}` version "
f"`{retrieve_equal_version(requirement.specifier).version}`"
for requirement in removed
]
)
return "\r\n".join(description)
def main():
args = parser().parse_args()
(added, updated, removed) = compare_requirements(args.requirements_file)
added, updated, removed = compare_requirements(args.requirements_file)
args.o.write_text(generate_changes(added, updated, removed))
......
......@@ -8,17 +8,19 @@ depandabot:
image: python:${IMAGE_TAG}
variables:
PYTHON_SETUP: pip install pip-tools packaging
PYTHON_SETUP: pip install pip-tools
GITLAB_API_URL: "${CI_SERVER_HOST}"
REQUIREMENTS_FILE_PATH: "requirements.in"
OUTPUT_FILE_PATH: "requirements${IMAGE_TAG}.txt"
script:
- !reference [.python_install, script]
- DEPS_BRANCH="depandabot/requirements-txt/$(date +%s)"
- |
COMMIT_MESSAGE="build(deps): bump new versions"
- $([ -f ${REQUIREMENTS_FILE_PATH} ]) && ACTION="update" || ACTION="create"
- pip-compile --quiet -o ${REQUIREMENTS_FILE_PATH}
- if [ -n "$(git status --porcelain ${REQUIREMENTS_FILE_PATH})" ]; then
- $([ -f ${OUTPUT_FILE_PATH} ]) && ACTION="update" || ACTION="create"
- pip-compile --quiet -o ${OUTPUT_FILE_PATH} ${REQUIREMENTS_FILE_PATH}
- if [ -n "$(git status --porcelain ${OUTPUT_FILE_PATH})" ]; then
- |
curl --header "Authorization: Bearer ${DEPANDABOT_TOKEN}" \
--form "branch=$DEPS_BRANCH" \
......@@ -29,10 +31,10 @@ depandabot:
--form "branch=$DEPS_BRANCH" \
--form "commit_message=$COMMIT_MESSAGE" \
--form "actions[][action]=$ACTION" \
--form "actions[][file_path]=${REQUIREMENTS_FILE_PATH}" \
--form "actions[][content]=<${REQUIREMENTS_FILE_PATH}" \
--form "actions[][file_path]=${OUTPUT_FILE_PATH}" \
--form "actions[][content]=<${OUTPUT_FILE_PATH}" \
"https://${GITLAB_API_URL}/api/v4/projects/${CI_PROJECT_ID}/repository/commits"
- python compare.py -o description.md ${REQUIREMENTS_FILE_PATH}
- python compare.py -o description.md ${OUTPUT_FILE_PATH}
- |
curl --header "Authorization: Bearer ${DEPANDABOT_TOKEN}" \
--form "source_branch=$DEPS_BRANCH" \
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment