From 5cbd540fde202a00461cfa101df5e9955461c2e2 Mon Sep 17 00:00:00 2001 From: Karstein Phobic Nyvold Kvistad Date: Sun, 26 Apr 2026 00:53:10 +0200 Subject: [PATCH] bump_project_version: resume from GVL when Project Information missing Previously, when a project had no Project Information node (e.g. one created from the Standard template via create_project), the bump flow read pi.version as None, the seed-check fired, and every call re-seeded to 1.0.0.0 -- subsequent revision/minor/major bumps were no-ops because the script never saw the actual current version. Surfaced on MCPTest2 today: bumping revision after editing PLC_PRG returned '1.0.0.0' instead of '1.0.1.0' because the seed kept firing. Fix: when Project Information is missing, fall back to reading the existing _MCP_PROJECT_VERSION.sVersion via the textual_declaration of the GVL we ourselves maintain. So the source-of-truth chain is: pi.version (when Project Information exists) -> falls back to GVL.sVersion (when Project Information missing but the GVL has been written by a prior bump) -> falls back to seed at 1.0.0.0 (true first-run, no GVL yet) Implementation: read_version_from_gvl(primary_project) walks the active Application's children for the named GVL and parses the sVersion := '...' literal out of its textual_declaration with a 4-part regex. Returns None if the GVL doesn't exist OR its decl doesn't match the expected shape; caller treats None as "no prior version, seed". Soft-fails on any access exception (the bump is the primary outcome, this is just resume-from-state). This is the kind of "every arising problem fixed at the fork, not worked around in one-offs" hygiene the user called out. --- src/scripts/bump_project_version.py | 44 +++++++++++++++++++++++++++-- 1 file changed, 42 insertions(+), 2 deletions(-) diff --git a/src/scripts/bump_project_version.py b/src/scripts/bump_project_version.py index 607cd55..be63008 100644 --- a/src/scripts/bump_project_version.py +++ b/src/scripts/bump_project_version.py @@ -1,4 +1,4 @@ -import sys, scriptengine as script_engine, traceback +import sys, scriptengine as script_engine, traceback, re # Bumps one part of the 4-part Project Information.version field of the # primary project. Convention (per CODESYS / 3S / WAGO library practice): @@ -58,6 +58,42 @@ def parse_version(v): return tuple(nums) +def read_version_from_gvl(primary_project): + """When Project Information is missing, read the current version back + from the runtime anchor GVL (_MCP_PROJECT_VERSION.sVersion) so subsequent + bumps can resume from the actual current state instead of re-seeding to + 1.0.0.0 on every call. Returns the version string or None if the GVL + doesn't exist yet (true first-run).""" + try: + app = getattr(primary_project, 'active_application', None) + except Exception: + app = None + if app is None: + try: + apps = primary_project.find('Application', True) + if apps: + app = apps[0] + except Exception: + pass + if app is None: + return None + try: + for child in app.get_children(False): + try: + if child.get_name() != VERSION_GVL_NAME: + continue + decl = child.textual_declaration.text or '' + m = re.search(r"sVersion\s*:\s*STRING\s*:=\s*'(\d+\.\d+\.\d+\.\d+)'", decl) + if m: + return m.group(1) + return None + except Exception: + pass + except Exception: + pass + return None + + def maintain_version_gvl(primary_project, version_str): """Find or create the _MCP_PROJECT_VERSION GVL under the active Application, and set its declaration so the running PLC carries the @@ -179,7 +215,11 @@ try: "maintained. To add the Project Information node, open the " "Project menu -> Project Information in the IDE; subsequent bumps " "will then update both metadata and GVL.") - before_raw = None + # Fall back to reading the existing GVL so we resume from the actual + # current version instead of re-seeding to 1.0.0.0 every call. + before_raw = read_version_from_gvl(primary_project) + if before_raw: + print("DEBUG: Project Information missing, resuming from GVL: %s" % before_raw) else: before_raw = pi.version before_str = str(before_raw) if before_raw is not None else None