Browse Source

adjusted the mbp_build script to the new mbp workbook groups

master
Holger Frey 3 weeks ago
parent
commit
bb1dbabd50
  1. 419
      work_helpers/sg_mbp_build.py

419
work_helpers/sg_mbp_build.py

@ -1,195 +1,236 @@ @@ -1,195 +1,236 @@
import click
import shutil
import pathlib
import pyperclip
import shutil
import sys
from pathlib import Path
from typing import Iterable
from dataclasses import dataclass
from datetime import datetime
from ._natural_sort import natural_sort
Pathlike = str | pathlib.Path
DEVELOPER_DRIVE = Path("/mnt/e/")
PATH_ISSUES = DEVELOPER_DRIVE / "Safeguard-MBP-issues"
PATH_WORKBOOKS = DEVELOPER_DRIVE / "Safeguard MBP Workbooks"
PATH_WIN_DESKTOP = Path("/mnt/c/Users/Holgi/Desktop")
PATH_WIN_DESKTOP = pathlib.Path("/mnt/c/Users/Holgi/Desktop")
TODAY = datetime.now().strftime("%y%m%d")
CRLF = "\r\n"
EXCEL_CHANGELOGS = {
"changes mbp {version} asqc.txt": "L1",
"changes mbp {version} dry-1.txt": "L1",
"changes mbp {version} dry-2.txt": "L1",
"changes mbp {version} hqc.txt": "J1",
"changes mbp {version} hyb.txt": "J1",
"changes mbp {version} mqc.txt": "J1",
"changes mbp {version} reg.txt": "J1",
GROUPS = {
"QC": ["ASQC, HQC, MQC"],
"Print": ["Dry-1, Dry-2"],
"Production": ["Hyb", "Reg"],
}
GROUP_FOLDER_PREFIX = "Safeguard-MBP-"
GROUP_FOLDER_SUFFIX = "-Changes"
EXCEL_CHANGELOG_HEADERS = [
"Sheet\tWell\tContents\tComment",
"-----\t----\t--------\t-------",
"",
]
WORKBOOKS_MAP = {
"MBP ASQC.xlsx": "MBP {version} ASQC.xlsx",
"MBP Dry-1.xlsx": "MBP {version} Dry-1.xlsx",
"MBP Dry-2.xlsx": "MBP {version} Dry-2.xlsx",
"MBP HQC.xlsx": "MBP {version} HQC.xlsx",
"MBP Hyb.xlsx": "MBP {version} Hyb.xlsx",
"MBP MQC.xlsx": "MBP {version} MQC.xlsx",
"MBP Reg.xlsx": "MBP {version} Reg.xlsx",
EXCEL_CHANGELOGS = {
"QC": {
"changes mbp qc asqc {version}.txt": "L1",
"changes mbp qc hqc {version}.txt": "J1",
"changes mbp qc mqc {version}.txt": "J1",
},
"Print": {
"changes mbp print dry-1 {version}.txt": "L1",
"changes mbp print dry-2 {version}.txt": "L1",
},
"Production": {
"changes mbp production hyb {version}.txt": "J1",
"changes mbp production reg {version}.txt": "J1",
},
}
def _folder_content(folder):
## Exception classes
class MBPExcecption(Exception):
pass
# common functions and helper functions
def _to_int(text: str, default=0) -> int:
try:
return int(text)
except (ValueError, TypeError):
return default
def _folder_content(folder: Pathlike) -> Iterable[pathlib.Path]:
folder = pathlib.Path(folder)
nondotted = (i for i in folder.iterdir() if not i.stem.startswith("."))
return (i for i in nondotted if not i.stem.startswith("~"))
def _files_in_folder(folder, suffix):
def _files_in_folder(folder: Pathlike, suffix: str) -> Iterable[pathlib.Path]:
folder = pathlib.Path(folder)
files = (f for f in _folder_content(folder) if f.is_file())
return (f for f in files if f.suffix == suffix)
def get_latest_version(parent=PATH_ISSUES):
folders = (i for i in _folder_content(parent) if i.is_dir())
versions = natural_sort(f.name for f in folders if f.stem.lower().startswith("v"))
return versions[-1]
def _get_workbook_folder(group: str) -> pathlib.Path:
path = pathlib.Path("/") / "mnt" / "e" / f"Safeguard MBP {group} Workbooks"
if not path.is_dir():
msg = "Workbook folder {path} does not exist"
raise MBPExcecption(msg)
return path
def get_next_version(parent=PATH_ISSUES, echo_current=True):
latest = get_latest_version(parent)
if echo_current:
print("current version:", latest)
def _get_changelog_path(folder: Pathlike) -> pathlib.Path:
textfiles = _files_in_folder(folder, ".txt")
return next(f for f in textfiles if f.stem.lower().startswith("change"))
try:
head, tail = latest.rsplit(".", 1)
next_minor = int(tail) + 1
next_version = f"{head}.{next_minor}"
except:
next_version = ""
return next_version
def _list_current_frms(group: str, build_version: str):
source = _get_workbook_folder(group)
search_version = build_version.removesuffix(TODAY)
all_folders = (f for f in source.iterdir() if f.is_dir())
all_frms = (f for f in all_folders if "frm" in f.name.lower())
return [f for f in all_frms if search_version in f.name]
def create_new_version_folder(new_version, parent=PATH_ISSUES):
new_folder_path = parent / new_version
if new_folder_path.exists():
print(f"Folder for version {new_version} already exists, aborting")
return
new_folder_path.mkdir()
return new_folder_path
def _get_issue_numbers(group: str, build_version: str):
print(list(_list_current_frms(group, build_version)))
for path in _list_current_frms(group, build_version):
rest, issue_info = path.name.lower().split("issue")
issue_info = issue_info.removeprefix("s") # might be "issues"
issue, *rest = issue_info.strip().split()
yield issue.strip(" ,")
def create_excel_changelogs(new_version, parent):
for name, cell in EXCEL_CHANGELOGS.items():
new_file = parent / name.format(version=new_version)
with new_file.open("w") as fh:
data_line = "\t".join(["Settings", cell, new_version, ""])
content_lines = EXCEL_CHANGELOG_HEADERS + [data_line, "", ""]
fh.write(CRLF.join(content_lines))
def _extract_changes_from_log(
cwd: Pathlike, group: str, build_version: str
) -> Iterable[str]:
issue_numbers = set(_get_issue_numbers(group, build_version))
changelog = _get_changelog_path(cwd)
for line in changelog.read_text().splitlines():
for issue in issue_numbers:
if issue in line:
yield line
def create_changelog_entry(new_version, parent=PATH_ISSUES):
textfiles = _files_in_folder(parent, ".txt")
changelog = next(f for f in textfiles if f.stem.lower().startswith("change"))
content = []
with changelog.open("r") as fh:
stripped_lines = (line.rstrip() for line in fh)
for line in stripped_lines:
content.append(line)
if line.startswith("----"):
content.append("")
content.append(f"{new_version}, work in progress:")
content.append(" - The following Workbooks did not have any changes: ASQC, Dry-1, Dry-2, Hyb, HQC, MQC, Reg")
with changelog.open("w") as fh:
fh.write(CRLF.join(content))
def _get_group_from_folder(folder: Pathlike) -> str:
name = pathlib.Path(folder).name
middle = name.removeprefix(GROUP_FOLDER_PREFIX).removesuffix(GROUP_FOLDER_SUFFIX)
if middle in GROUPS:
return middle
msg = f"Folder '{name}' is not an MBP group folder"
raise MBPExcecption(msg)
def get_changelog_path():
textfiles = _files_in_folder(PATH_ISSUES, ".txt")
return next(f for f in textfiles if f.stem.lower().startswith("change"))
def copy_changelog(destination, build_version):
changelog = get_changelog_path()
new_path = destination / f"CHANGELOG {build_version}.txt"
print(changelog.name, "->", new_path)
shutil.copyfile(changelog, new_path)
def _get_latest_version(folder: Pathlike) -> "Version":
dir_names = [i.name for i in pathlib.Path(folder).iterdir() if i.is_dir()]
version_names = [name for name in dir_names if name.startswith("v")]
versions = [Version.from_name(name) for name in version_names]
sorted_versions = sorted(versions, key=lambda x: x.to_tuple())
return sorted_versions[-1]
def copy_workbook_changelogs(destination, latest, build_version):
source = PATH_ISSUES / latest
textfiles = _files_in_folder(source, ".txt")
logs = (f for f in textfiles if f.stem.lower().startswith("change"))
for log_file in logs:
new_name = log_file.name.replace(latest, build_version)
new_path = destination / new_name
print(log_file.name, "->", new_path)
shutil.copyfile(log_file, new_path)
## data classes
@dataclass
class Version:
major: int
layout: int
minor: int
@classmethod
def from_name(cls, name: str) -> "Version":
parts = name.removeprefix("v").split(".") + [None, None]
args = tuple([_to_int(part) for part in parts[:3]])
return cls(*args)
def to_tuple(self) -> tuple[int, int, int]:
return (self.major, self.layout, self.minor)
def bump(self) -> None:
cls = type(self)
return cls(self.major, self.layout, self.minor + 1)
def __str__(self) -> str:
return f"v{self.major}.{self.layout}.{self.minor}"
def copy_workbooks(destination, build_version):
all_xls_files = _files_in_folder(PATH_WORKBOOKS, ".xlsx")
## functions for `sg_mbp_build`
def copy_workbooks(group: str, destination: Pathlike, build_version: str) -> None:
source = _get_workbook_folder(group)
all_xls_files = _files_in_folder(source, ".xlsx")
mbp_files = (f for f in all_xls_files if f.name.lower().startswith("mbp"))
for excel_file in mbp_files:
new_name = WORKBOOKS_MAP[excel_file.name]
new_name = f"{excel_file.stem} {build_version}{excel_file.suffix}"
new_path = destination / new_name.format(version=build_version)
print(excel_file.name, "->", new_path)
shutil.copyfile(excel_file, new_path)
def collect_current_frms(build_version):
all_folders = (f for f in PATH_WORKBOOKS.iterdir() if f.is_dir())
all_frms = (f for f in all_folders if "frm" in f.name.lower())
return [f for f in all_frms if f.name.endswith(build_version)]
def copy_frms(destination, build_version):
all_folders = (f for f in PATH_WORKBOOKS.iterdir() if f.is_dir())
all_frms = (f for f in all_folders if "frm" in f.name.lower())
current_frms = collect_current_frms(build_version)
def copy_frms(group: str, destination: Pathlike, build_version: str) -> None:
current_frms = _list_current_frms(group, build_version)
for folder in current_frms:
new_path = destination / folder.name
print(folder.name, "->", new_path)
shutil.copytree(folder, new_path)
def get_issue_numbers(build_version):
for path in collect_current_frms(build_version):
rest, issue_info = path.name.lower().split("issue")
issue, *rest = issue_info.strip().split()
yield issue.strip(" ,")
def copy_workbook_changelogs(
cwd: Pathlike, destination: Pathlike, latest: Version, build_version: str
) -> None:
source = pathlib.Path(cwd) / str(latest)
textfiles = _files_in_folder(source, ".txt")
logs = (f for f in textfiles if f.stem.lower().startswith("change"))
for log_file in logs:
new_name = log_file.name.replace(str(latest), build_version)
new_path = destination / new_name
print(log_file.name, "->", new_path)
shutil.copyfile(log_file, new_path)
def extract_changes_from_log(build_version):
issue_numbers = set(get_issue_numbers(build_version))
changelog = get_changelog_path()
for line in changelog.read_text().splitlines():
for issue in issue_numbers:
if issue in line:
yield line
def copy_changelog(cwd: Pathlike, destination: Pathlike, build_version: str) -> None:
changelog = _get_changelog_path(cwd)
new_path = pathlib.Path(destination) / f"CHANGELOG {build_version}.txt"
print(changelog.name, "->", new_path)
shutil.copyfile(changelog, new_path)
def get_announcement_text(dev_version, build_version, new_folder_name):
if not dev_version:
return "This is an official release, the message must be hand crafted"
latest = get_latest_version()
changes = list(extract_changes_from_log(build_version))
def get_announcement_text(
cwd: Pathlike,
group: str,
latest: Version,
build_version: str,
new_folder_name: Pathlike,
) -> str:
changes = list(_extract_changes_from_log(cwd, group, build_version))
if len(changes) == 1:
change_msg = "Only one change was introduced:"
else:
change_msg = "The changes made:"
if not build_version.endswith(TODAY):
dev_version = build_version.split(".")[-1]
version_note = (
f"As indicated by the letter '{dev_version}' at the end,"
" this version is intended for Freiburg only."
)
else:
version_note = "This is an official release version."
text = [
f"# New MBP Workbook Version {build_version}",
"Good News Everyone,",
f"there is a new MBP workbook version available: {build_version}",
(
f"As indicated by the letter '{dev_version}' at the end,"
" this version is intended for Freiburg only."
),
version_note,
change_msg,
"\n".join(changes),
"You can find this version at our Freiburg Shared Drive:",
@ -198,67 +239,127 @@ def get_announcement_text(dev_version, build_version, new_folder_name): @@ -198,67 +239,127 @@ def get_announcement_text(dev_version, build_version, new_folder_name):
f" {latest} /"
f" {new_folder_name}"
),
"Cheers,\nHolgi"
"Cheers,\nHolgi",
]
return "\n\n".join(text)
@click.command()
@click.option(
"-v",
"--version",
required=True,
prompt="new version",
default=get_next_version,
show_default="next minor version",
)
def sg_mbp_new_version(version):
"""
creates a new version folder, new excel changes files and modifies the overall changelog
in "E:\Safeguard-MBP-issues"
"""
folder = create_new_version_folder(version)
if folder is not None:
create_excel_changelogs(version, folder)
create_changelog_entry(version)
@click.command()
@click.option(
"-d",
"--dev_version",
prompt="Dev version i.e. 'c'",
required=True,
default="",
default=TODAY,
)
def sg_mbp_build(dev_version):
"""
Before running this command:
\b
- create a new versions folder e.g. "v4.9.2"
- make the requiered edits to the workbooks
- edit the changelog in "E:\Safeguard-MBP-issues"
- create a new versions folder in "E:\Safeguard-MBP-issues", e.g. "v3.9.49"
- note the changes in the excel changelogs in the created version folder
- edit the group changelog
The command will collect all data into one folder on the Desktop to be published
"""
latest = get_latest_version()
build_version = f"{latest}{dev_version}"
try:
cwd = pathlib.Path.cwd()
group = _get_group_from_folder(cwd)
latest = _get_latest_version(cwd)
build_version = f"{latest}.{dev_version}"
new_folder_name = f"{TODAY} MBP {group} {build_version}"
new_folder_path = PATH_WIN_DESKTOP / new_folder_name
if new_folder_path.exists():
raise MBPExcecption(f"Folder exists on desktop: {new_folder_name}")
else:
new_folder_path.mkdir()
copy_workbooks(group, new_folder_path, build_version)
copy_frms(group, new_folder_path, build_version)
copy_workbook_changelogs(cwd, new_folder_path, latest, build_version)
copy_changelog(cwd, new_folder_path, build_version)
announcement = get_announcement_text(
cwd, group, latest, build_version, new_folder_name
)
pyperclip.copy(announcement)
print(announcement)
except MBPExcecption as e:
sys.exit(str(e))
## functions for `sg_mbp_new_version`
def get_next_version() -> Version:
try:
cwd = pathlib.Path.cwd()
_get_group_from_folder(cwd) # may raise an exception
latest = _get_latest_version(cwd)
return latest.bump()
except MBPExcecption as e:
sys.exit(str(e))
new_folder_name = f"{TODAY} {build_version}"
new_folder_path = PATH_WIN_DESKTOP / new_folder_name
def create_new_version_folder(cwd: Pathlike, new_version: str) -> pathlib.Path:
new_folder_path = pathlib.Path(cwd) / new_version
if new_folder_path.exists():
raise IOError(f"Folder exists on desktop: {new_folder_name}")
else:
new_folder_path.mkdir()
msg = f"Folder for version {new_version} already exists"
raise MBPExcecption(msg)
new_folder_path.mkdir()
return new_folder_path
def create_excel_changelogs(folder: Pathlike, new_version: str) -> None:
folder = pathlib.Path(folder)
group = _get_group_from_folder(folder.parent)
for name, cell in EXCEL_CHANGELOGS[group].items():
new_file = folder / name.format(version=new_version)
with new_file.open("w") as fh:
data_line = "\t".join(["Settings", cell, new_version, ""])
content_lines = EXCEL_CHANGELOG_HEADERS + [data_line, "", ""]
fh.write(CRLF.join(content_lines))
copy_workbooks(new_folder_path, build_version)
copy_workbook_changelogs(new_folder_path, latest, build_version)
copy_changelog(new_folder_path, build_version)
copy_frms(new_folder_path, build_version)
announcement = get_announcement_text(dev_version, build_version, new_folder_name)
pyperclip.copy(announcement)
print(announcement)
def create_changelog_entry(cwd: Pathlike, new_version: str) -> None:
group = _get_group_from_folder(cwd)
workbooks = ", ".join(GROUPS[group])
changelog = _get_changelog_path(cwd)
content = []
with changelog.open("r") as fh:
stripped_lines = (line.rstrip() for line in fh)
for line in stripped_lines:
content.append(line)
if line.startswith("----"):
content.append("")
content.append(f"{new_version}, work in progress:")
content.append(
f" - The following Workbooks did not have any changes: {workbooks}"
)
with changelog.open("w") as fh:
fh.write(CRLF.join(content))
@click.command()
@click.option(
"-v",
"--version",
required=True,
prompt="new version",
default=get_next_version,
show_default="next minor version",
)
def sg_mbp_new_version(version):
"""
creates a new version folder, new excel changes files and modifies the overall changelog
in "E:\Safeguard-MBP-issues"
"""
cwd = pathlib.Path.cwd()
folder = create_new_version_folder(cwd, version)
create_excel_changelogs(folder, version)
create_changelog_entry(cwd, version)

Loading…
Cancel
Save