From 3da2cd3cf854954f0d1ba0c146eb9af9b2e26176 Mon Sep 17 00:00:00 2001 From: jpirnay Date: Sun, 1 Mar 2026 02:07:08 +0100 Subject: [PATCH] feat: Add git branch to version information on settings screen (#1225) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary * **What is the goal of this PR?** During my development I am frequently jumping from branch to branch flashing test versions on my device. It becomes sometimes quite difficult to figure out which version of the software I am currently looking at. * **What changes are included?** - Dev builds now display the current git branch in the version string shown on the Settings screen (e.g. 1.1.0-dev+feat-my-feature), making it easier to identify which firmware is running on the device when switching between branches frequently. - Release, RC, and slim builds are unaffected — they continue to set their version string statically in platformio.ini. after ## Additional Context A new PlatformIO pre-build script (scripts/git_branch.py) runs automatically before every dev build. It reads the base version from the [crosspoint] section of platformio.ini, queries git rev-parse --abbrev-ref HEAD for the current branch, and injects the combined string as the CROSSPOINT_VERSION preprocessor define. In a detached HEAD state it falls back to the short commit SHA. If git is unavailable it warns and falls back to unknown. The script can also be run directly with python scripts/git_branch.py for validation without triggering a full build. --- ### AI Usage While CrossPoint doesn't have restrictions on AI tools in contributing, please be transparent about their usage as it helps set the right context for reviewers. Did you use AI tools to help write this code? _**< YES | PARTIALLY | NO >**_ --- platformio.ini | 3 +- scripts/git_branch.py | 83 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 85 insertions(+), 1 deletion(-) create mode 100644 scripts/git_branch.py diff --git a/platformio.ini b/platformio.ini index 390812e9..3ace1ac6 100644 --- a/platformio.ini +++ b/platformio.ini @@ -46,6 +46,7 @@ board_build.partitions = partitions.csv extra_scripts = pre:scripts/build_html.py pre:scripts/gen_i18n.py + pre:scripts/git_branch.py ; Libraries lib_deps = @@ -62,7 +63,7 @@ lib_deps = extends = base build_flags = ${base.build_flags} - -DCROSSPOINT_VERSION=\"${crosspoint.version}-dev\" + ; CROSSPOINT_VERSION is set by scripts/git_branch.py (includes current branch) -DENABLE_SERIAL_LOG -DLOG_LEVEL=2 ; Set log level to debug for development builds diff --git a/scripts/git_branch.py b/scripts/git_branch.py new file mode 100644 index 00000000..5ff74a9b --- /dev/null +++ b/scripts/git_branch.py @@ -0,0 +1,83 @@ +""" +PlatformIO pre-build script: inject git branch into CROSSPOINT_VERSION for +the default (dev) environment. + +Results in a version string like: 1.1.0-dev+feat-koysnc-xpath +Release environments are unaffected; they set CROSSPOINT_VERSION in the ini. +""" + +import configparser +import os +import subprocess +import sys + + +def warn(msg): + print(f'WARNING [git_branch.py]: {msg}', file=sys.stderr) + + +def get_git_branch(project_dir): + try: + branch = subprocess.check_output( + ['git', 'rev-parse', '--abbrev-ref', 'HEAD'], + text=True, stderr=subprocess.PIPE, cwd=project_dir + ).strip() + # Detached HEAD — show the short SHA instead + if branch == 'HEAD': + branch = subprocess.check_output( + ['git', 'rev-parse', '--short', 'HEAD'], + text=True, stderr=subprocess.PIPE, cwd=project_dir + ).strip() + # Strip characters that would break a C string literal + return ''.join(c for c in branch if c not in '"\\') + except FileNotFoundError: + warn('git not found on PATH; branch suffix will be "unknown"') + return 'unknown' + except subprocess.CalledProcessError as e: + warn(f'git command failed (exit {e.returncode}): {e.stderr.strip()}; branch suffix will be "unknown"') + return 'unknown' + except Exception as e: + warn(f'Unexpected error reading git branch: {e}; branch suffix will be "unknown"') + return 'unknown' + + +def get_base_version(project_dir): + ini_path = os.path.join(project_dir, 'platformio.ini') + if not os.path.isfile(ini_path): + warn(f'platformio.ini not found at {ini_path}; base version will be "0.0.0"') + return '0.0.0' + config = configparser.ConfigParser() + config.read(ini_path) + if not config.has_option('crosspoint', 'version'): + warn('No [crosspoint] version in platformio.ini; base version will be "0.0.0"') + return '0.0.0' + return config.get('crosspoint', 'version') + + +def inject_version(env): + # Only applies to the dev (default) environment; release envs set the + # version via build_flags in platformio.ini and are unaffected. + if env['PIOENV'] != 'default': + return + + project_dir = env['PROJECT_DIR'] + base_version = get_base_version(project_dir) + branch = get_git_branch(project_dir) + version_string = f'{base_version}-dev+{branch}' + + env.Append(CPPDEFINES=[('CROSSPOINT_VERSION', f'\\"{version_string}\\"')]) + print(f'CrossPoint build version: {version_string}') + + +# PlatformIO/SCons entry point — Import and env are SCons builtins injected at runtime. +# When run directly with Python (e.g. for validation), a lightweight fake env is used +# so the git/version logic can be exercised without a full build. +try: + Import('env') # noqa: F821 # type: ignore[name-defined] + inject_version(env) # noqa: F821 # type: ignore[name-defined] +except NameError: + class _Env(dict): + def Append(self, **_): pass + + _project_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + inject_version(_Env({'PIOENV': 'default', 'PROJECT_DIR': _project_dir}))