feat: Add git branch to version information on settings screen (#1225)

## 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.
<img width="480" height="800" alt="after"
src="https://github.com/user-attachments/assets/d2ab3d69-ab6b-47a1-8eb7-1b40b1d3b106"
/>


## 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
>**_
This commit is contained in:
jpirnay
2026-03-01 02:07:08 +01:00
committed by GitHub
parent 88c49b8bed
commit 3da2cd3cf8
2 changed files with 85 additions and 1 deletions

View File

@@ -46,6 +46,7 @@ board_build.partitions = partitions.csv
extra_scripts = extra_scripts =
pre:scripts/build_html.py pre:scripts/build_html.py
pre:scripts/gen_i18n.py pre:scripts/gen_i18n.py
pre:scripts/git_branch.py
; Libraries ; Libraries
lib_deps = lib_deps =
@@ -62,7 +63,7 @@ lib_deps =
extends = base extends = base
build_flags = build_flags =
${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 -DENABLE_SERIAL_LOG
-DLOG_LEVEL=2 ; Set log level to debug for development builds -DLOG_LEVEL=2 ; Set log level to debug for development builds

83
scripts/git_branch.py Normal file
View File

@@ -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}))