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:
@@ -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
83
scripts/git_branch.py
Normal 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}))
|
||||||
Reference in New Issue
Block a user