Skip to content

Conversation

@edbordin
Copy link

@edbordin edbordin commented Sep 22, 2025

Minor adjustment to the work done in this commit so that changes to version.h don't flow through anywhere they are included and trigger a rebuild. Totally understandable if you're happy with the current approach using #define though!

Summary by CodeRabbit

  • New Features

    • Firmware version and build timestamp are now exposed as readable values for consistent display across the app.
  • Refactor

    • Build metadata generation switched from preprocessor macros to linkable constants for more reliable usage.
  • Chores

    • Build configuration broadened to include all version-related sources across relevant environments.
    • VCS ignore rules updated to match the new version metadata output.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Sep 22, 2025

Walkthrough

Script output moved from a generated header to a compiled source: the pre-build script now emits src/version.cpp (raw string definitions), a new header src/version.h declares extern C strings, PlatformIO build filters now match any version.*, and .gitignore now ignores src/version.cpp instead of src/version.h.

Changes

Cohort / File(s) Summary of changes
Version metadata generator & API
scripts/auto_firmware_version.py, src/version.h
Script renamed helper functions and now returns raw strings; it writes src/version.cpp containing C-style definitions (const char ... = "...") while src/version.h declares extern const char BUILD_GIT_VERSION[]; and extern const char BUILD_TIMESTAMP[];.
Build configuration filters
platformio.ini
Broadened build_src_filter for multiple environments to include version.* (any file matching), replacing the previous single version.h entry; other include/exclude patterns retained.
Ignore list update
.gitignore
Replaced ignore entry for src/version.h with src/version.cpp.

Sequence Diagram(s)

sequenceDiagram
    autonumber
    participant Dev as Developer
    participant PIO as PlatformIO
    participant Script as auto_firmware_version.py
    participant FS as src/version.cpp
    participant Header as src/version.h
    participant CC as Compiler/Linker

    Dev->>PIO: trigger build
    PIO->>Script: run pre-build script
    Script->>FS: write raw const char definitions (BUILD_GIT_VERSION, BUILD_TIMESTAMP)
    Script->>Header: ensure header declares extern const char symbols
    PIO->>CC: compile sources (build_src_filter includes version.*)
    CC-->>Dev: linked firmware binary
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

I twitch my whiskers, nibble a line,
From macros to C-strings my burrow shines.
A tiny .cpp hops into place,
Filters widened—version finds its space.
Hop on, build; I guard the trace. 🐇✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title clearly and concisely states the primary intent of the change — adding the build timestamp at link-time to avoid unnecessary rebuilds — and the PR description and file summaries confirm this is the main goal (the generation script now emits extern BUILD_TIMESTAMP/BUILD_GIT_VERSION into src/version.cpp and adds src/version.h). The phrasing is specific, readable, and relevant to the actual changes.
✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (3)
platformio.ini (1)

64-64: LGTM – source filters now include version. where needed.*

This confines rebuilds to version.cpp + link, as intended.

If all envs need the generated version.cpp, consider moving:

  • extra_scripts = pre:scripts/auto_firmware_version.py
    …to [env] to DRY, unless any env must opt out.

Also applies to: 83-83, 95-95

scripts/auto_firmware_version.py (2)

6-11: Harden git describe invocation and add a fallback.

Capture stderr, check return code, and fall back to short SHA if tags are absent. Also addresses the S607 hint by avoiding silent failures.

-def get_firmware_specifier():
-    ret = subprocess.run(["git", "describe", "--tags", "--dirty", "--exclude", "nightly"], stdout=subprocess.PIPE, text=True) #Uses any tags
-    build_version = ret.stdout.strip()
-    print ("Build version: " + build_version)
-    return build_version
+def get_firmware_specifier():
+    ret = subprocess.run(
+        ["git", "describe", "--tags", "--dirty", "--exclude", "nightly"],
+        stdout=subprocess.PIPE,
+        stderr=subprocess.PIPE,
+        text=True,
+    )
+    if ret.returncode != 0 or not ret.stdout.strip():
+        fallback = subprocess.run(
+            ["git", "rev-parse", "--short", "HEAD"],
+            stdout=subprocess.PIPE,
+            stderr=subprocess.PIPE,
+            text=True,
+        )
+        build_version = (fallback.stdout or "").strip() or "unknown"
+    else:
+        build_version = ret.stdout.strip()
+    print("Build version: " + build_version)
+    return build_version

Optional: resolve S607 fully by locating git explicitly:

# add at top-level
import shutil
git = shutil.which("git") or "git"
# then use [git, "describe", ...] and [git, "rev-parse", ...]

17-22: Write to the PlatformIO src dir via env to avoid path assumptions; keep extern in the definition.

Use PROJECTSRC_DIR in case the project layout changes; and keep extern on the definition to ensure external linkage for const.

-with open('src/version.cpp', 'w') as f:
+with open(env.subst("${PROJECTSRC_DIR}") + "/version.cpp", "w") as f:
     f.write(
-        f"""#include <Arduino.h>
-extern const String BUILD_GIT_VERSION = "{get_firmware_specifier()}";
-extern const String BUILD_TIMESTAMP = "{get_time_specifier()}";
-""")
+        f"""#include <Arduino.h>
+extern const String BUILD_GIT_VERSION = "{get_firmware_specifier()}";
+extern const String BUILD_TIMESTAMP = "{get_time_specifier()}";
+""")

If you adopt the char[] recommendation from version.h, emit arrays instead to avoid heap allocations:

#include <Arduino.h>
extern const char BUILD_GIT_VERSION[] = "{get_firmware_specifier()}";
extern const char BUILD_TIMESTAMP[]   = "{get_time_specifier()}";
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3e3db58 and 0f54e41.

📒 Files selected for processing (4)
  • .gitignore (1 hunks)
  • platformio.ini (3 hunks)
  • scripts/auto_firmware_version.py (1 hunks)
  • src/version.h (1 hunks)
🧰 Additional context used
🪛 Ruff (0.13.1)
scripts/auto_firmware_version.py

7-7: Starting a process with a partial executable path

(S607)

🔇 Additional comments (1)
.gitignore (1)

11-11: LGTM – ignore the generated translation unit.

Ignoring src/version.cpp is correct now that the build emits a .cpp for link-time constants.

Comment on lines +12 to +15
def get_time_specifier():
build_timestamp = datetime.datetime.now(datetime.UTC).strftime("%Y-%m-%dT%H:%M:%SZ")
build_flag = "#define BUILD_TIMESTAMP \"" + build_timestamp + "\""
print ("Build date: " + build_timestamp)
return build_flag
return build_timestamp
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Fix Python 3.11-only datetime.UTC usage (breaks on older PlatformIO Python).

Use datetime.timezone.utc for broader compatibility.

 def get_time_specifier():
-    build_timestamp = datetime.datetime.now(datetime.UTC).strftime("%Y-%m-%dT%H:%M:%SZ")
+    build_timestamp = datetime.datetime.now(datetime.timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")
     print ("Build date: " + build_timestamp)
     return build_timestamp
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
def get_time_specifier():
build_timestamp = datetime.datetime.now(datetime.UTC).strftime("%Y-%m-%dT%H:%M:%SZ")
build_flag = "#define BUILD_TIMESTAMP \"" + build_timestamp + "\""
print ("Build date: " + build_timestamp)
return build_flag
return build_timestamp
def get_time_specifier():
build_timestamp = datetime.datetime.now(datetime.timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")
print ("Build date: " + build_timestamp)
return build_timestamp
🤖 Prompt for AI Agents
In scripts/auto_firmware_version.py around lines 12 to 15, the code uses
datetime.UTC which exists only in Python 3.11+ and breaks on older PlatformIO
Python; replace datetime.UTC with datetime.timezone.utc (and ensure
datetime.timezone is available via the existing import) so the timestamp uses
timezone-aware UTC compatible with older Python versions, then keep the same
strftime and return/print logic.

@sonarqubecloud
Copy link

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
scripts/auto_firmware_version.py (1)

6-10: Harden git invocation: check failures and avoid PATH‑only exec (Ruff S607).

Add check=True and resolve git via shutil.which; fall back to "unknown" if unavailable.

 def get_firmware_specifier():
-    ret = subprocess.run(["git", "describe", "--tags", "--dirty", "--exclude", "nightly"], stdout=subprocess.PIPE, text=True) #Uses any tags
-    build_version = ret.stdout.strip()
-    print ("Build version: " + build_version)
-    return build_version
+    git_exe = shutil.which("git")
+    if not git_exe:
+        print("git not found; using 'unknown'")
+        return "unknown"
+    ret = subprocess.run(
+        [git_exe, "describe", "--tags", "--dirty", "--exclude", "nightly"],
+        stdout=subprocess.PIPE,
+        text=True,
+        check=True,
+    )
+    build_version = ret.stdout.strip() or "unknown"
+    print("Build version: " + build_version)
+    return build_version

Additional imports (outside this hunk):

import shutil
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0f54e41 and 6193e48.

📒 Files selected for processing (2)
  • scripts/auto_firmware_version.py (1 hunks)
  • src/version.h (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/version.h
🧰 Additional context used
🪛 Ruff (0.13.1)
scripts/auto_firmware_version.py

7-7: Starting a process with a partial executable path

(S607)

🔇 Additional comments (1)
scripts/auto_firmware_version.py (1)

12-15: Fix Python 3.11‑only datetime.UTC usage.

Use datetime.timezone.utc for compatibility with older PlatformIO Python.

 def get_time_specifier():
-    build_timestamp = datetime.datetime.now(datetime.UTC).strftime("%Y-%m-%dT%H:%M:%SZ")
+    build_timestamp = datetime.datetime.now(datetime.timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")
     print ("Build date: " + build_timestamp)
     return build_timestamp

Comment on lines +17 to +21
with open('src/version.cpp', 'w') as f:
f.write(
'#pragma once\n' +
'#ifndef GIT_VERSION_H\n' +
'#define GIT_VERSION_H\n' +
get_firmware_specifier_build_flag() + '\n' +
get_time_specifier_build_flag() + '\n'
'#endif\n'
)
f"""extern const char BUILD_GIT_VERSION[] = "{get_firmware_specifier()}";
extern const char BUILD_TIMESTAMP[] = "{get_time_specifier()}";
""")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Make generated C++ string literals robust and path/line‑ending stable.

Raw string literals avoid breakage if a tag ever contains quotes; also write to PROJECTSRC_DIR with UTF‑8 and LF.

-with open('src/version.cpp', 'w') as f:
-    f.write(
-        f"""extern const char BUILD_GIT_VERSION[] = "{get_firmware_specifier()}";
-extern const char BUILD_TIMESTAMP[] = "{get_time_specifier()}";
-""")
+with open(os.path.join(env.subst("$PROJECTSRC_DIR"), "version.cpp"), "w", encoding="utf-8", newline="\n") as f:
+    ver = get_firmware_specifier()
+    ts = get_time_specifier()
+    f.write(
+        f'extern const char BUILD_GIT_VERSION[] = R"({ver})";\n'
+        f'extern const char BUILD_TIMESTAMP[] = R"({ts})";\n'
+    )

Additional import (outside this hunk):

import os

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant