Skill/scripts/append_parameter.py

132 lines
5.4 KiB
Python
Executable File

#!/usr/bin/env python3
"""Add one or more new parameters to a single typeid's template sheet, bump that typeid's
versions, and record the change in the global changelog.
Versioning is **per typeid**: adding a parameter to (say) SCH means there's a new SCH
template, so SCH's template_version bumps v1->v2, and on the back of that its skill_version
bumps v1->v2 too. Only SCH moves; every other typeid keeps its versions. Those two numbers
are what fill_templates later stamps into the SCH sheet's rows (columns B and C).
The new column is appended at the END of the sheet (as requested), styled like the other
headers. Then versions.json is bumped and one entry is written to CHANGELOG.xlsx.
python append_parameter.py --typeid SCH \
--param "Reverse Recovery Time(ns)" --param "Diode Capacitance(pF)" \
--desc "Added Trr and Cd for SMPS rectifier derating"
After running, push the updated template.xlsx + versions.json + CHANGELOG.xlsx to the SKILL
repo (and, per the workflow, the same change flows to the library repo copies).
"""
import argparse, datetime, os
import openpyxl
from copy import copy
from openpyxl.styles import Font, PatternFill, Border, Side, Alignment
from common import (TEMPLATE_XLSX, CHANGELOG_XLSX, CHANGELOG_HEADERS,
bump_versions, resolve_operator)
GREEN = "B6D7A8"; GRAY = "BFBFBF"
def _style_header(new_cell, ref_cell):
"""Make an appended header look like the sheet's existing headers."""
for attr in ("font", "fill", "border", "alignment", "number_format"):
try:
setattr(new_cell, attr, copy(getattr(ref_cell, attr)))
except Exception:
pass
def append_params(template_path, typeid, params):
wb = openpyxl.load_workbook(template_path)
if typeid not in wb.sheetnames:
raise SystemExit(f"no sheet '{typeid}' in template; is it a valid typeid?")
ws = wb[typeid]
headers = [ws.cell(1, c).value for c in range(1, ws.max_column + 1)]
added = []
for p in params:
if p in headers:
print(f" ! '{p}' already exists in {typeid} - skipping")
continue
col = ws.max_column + 1
cell = ws.cell(1, col, p)
_style_header(cell, ws.cell(1, 1))
headers.append(p)
added.append(p)
if not added:
raise SystemExit("nothing to add (all parameters already present)")
wb.save(template_path)
return added
def _thin():
s = Side(style="thin", color=GRAY)
return Border(left=s, right=s, top=s, bottom=s)
def _new_changelog_book():
"""Create the changelog workbook with a styled header row."""
wb = openpyxl.Workbook()
ws = wb.active
ws.title = "Changelog"
for c, h in enumerate(CHANGELOG_HEADERS, start=1):
cell = ws.cell(1, c, h)
cell.font = Font(name="Calibri", bold=True)
cell.fill = PatternFill("solid", fgColor=GREEN)
cell.border = _thin()
cell.alignment = Alignment(horizontal="center", vertical="center")
for col, w in zip("ABCDEF", (18, 10, 14, 16, 50, 22)):
ws.column_dimensions[col].width = w
ws.freeze_panes = "A2"
return wb
def write_changelog(typeid, added, old, new, desc, by="", when=None):
"""Append one row to the Excel changelog for a typeid's template/version change.
Columns: Date | Typeid | Skill Version | Template Version | Description | By. The version
columns show the NEW versions; Description is the note (or the added params); By is who
made the change (the operator)."""
when = when or datetime.datetime.now()
detail = desc or ("Added parameter(s): " + ", ".join(added))
if os.path.exists(CHANGELOG_XLSX):
wb = openpyxl.load_workbook(CHANGELOG_XLSX)
ws = wb["Changelog"] if "Changelog" in wb.sheetnames else wb.active
else:
wb = _new_changelog_book()
ws = wb.active
row = [when.strftime("%Y-%m-%d %H:%M"), typeid,
f"v{new['skill_version']}", f"v{new['template_version']}", detail, by or ""]
r = ws.max_row + 1
for c, v in enumerate(row, start=1):
cell = ws.cell(r, c, v)
cell.border = _thin()
cell.alignment = Alignment(vertical="center",
wrap_text=(c == 5), horizontal="left")
wb.save(CHANGELOG_XLSX)
return CHANGELOG_XLSX
def main():
ap = argparse.ArgumentParser()
ap.add_argument("--typeid", required=True, help="e.g. SCH, MOS, LDO")
ap.add_argument("--param", required=True, action="append",
help="new column header; repeat for several")
ap.add_argument("--desc", default="", help="what/why - goes in the changelog")
ap.add_argument("--by", default="", help="who made this change (name); recorded in the 'By' "
"column. If omitted, the operator identity is resolved automatically.")
ap.add_argument("--template", default=TEMPLATE_XLSX)
a = ap.parse_args()
by = a.by or (resolve_operator()[0] or "")
added = append_params(a.template, a.typeid, a.param)
old, new = bump_versions(a.typeid)
cl = write_changelog(a.typeid, added, old, new, a.desc, by=by)
print(f"Added to {a.typeid}: {', '.join(added)}" + (f" (by {by})" if by else ""))
print(f"{a.typeid}: template v{old['template_version']}->v{new['template_version']}, "
f"skill v{old['skill_version']}->v{new['skill_version']}")
print(f"Changelog updated: {cl}")
print("Now push template.xlsx + versions.json + CHANGELOG.xlsx to the SKILL repo.")
if __name__ == "__main__":
main()