Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ __pycache__/
*.py[cod]
*$py.class

# Auto-generated version file
src/malla/_version.py

# C extensions
*.so

Expand Down
23 changes: 20 additions & 3 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
[build-system]
requires = ["hatchling"]
requires = ["hatchling", "uv-dynamic-versioning"]
build-backend = "hatchling.build"

[project]
name = "malla"
version = "0.1.0"
dynamic = ["version"]
description = "A comprehensive web UI for browsing and analyzing Meshtastic mesh network health data"
readme = "README.md"
license = {file = "LICENSE"}
Expand Down Expand Up @@ -74,7 +74,24 @@ dev = [

# Hatch configuration
[tool.hatch.version]
path = "src/malla/__init__.py"
source = "uv-dynamic-versioning"

[tool.hatch.build.hooks.version]
path = "src/malla/_version.py"
template = '''
__version__ = "{version}"
'''

[tool.uv-dynamic-versioning]
vcs = "git"
# Use PEP440 style for Python compatibility
style = "pep440"
# Enable metadata to include commit hash when not on a tagged commit
metadata = true
# Include dirty flag to show uncommitted changes
dirty = true
# Fallback version when not in a git repository (e.g., when installed from PyPI)
fallback-version = "0.1.0"

[tool.hatch.build]
include = [
Expand Down
30 changes: 27 additions & 3 deletions src/malla/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,44 @@
A comprehensive web UI for browsing and analyzing Meshtastic mesh network health data.
"""

__version__ = "0.1.0"
__title__ = "Malla"
__description__ = "A comprehensive web UI for browsing and analyzing Meshtastic mesh network health data"
__author__ = "Malla Contributors"
__license__ = "MIT"

# Package-level imports for convenience
from .web_ui import create_app
# Import version from the auto-generated _version.py file
# This file is created by uv-dynamic-versioning during build
try:
from ._version import __version__
except ImportError:
# Fallback for development mode when package is not built
__version__ = "0.1.0.dev0+unknown"

__all__ = [
"create_app",
"__version__",
"get_version",
"__title__",
"__description__",
"__author__",
"__license__",
]


# get_version() simply returns __version__ which is set by uv-dynamic-versioning
def get_version():
"""
Get version information for the application.

Returns the version string set by uv-dynamic-versioning during build,
which includes git commit information for rolling releases.

Returns:
str: Version string from uv-dynamic-versioning or fallback
"""
return __version__


# Import create_app at the end to avoid circular import issues
# This import comes after all module-level definitions
from .web_ui import create_app # noqa: E402
2 changes: 1 addition & 1 deletion src/malla/templates/base.html
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@
<div class="container">
<div class="row">
<div class="col-md-6">
<small>Powered by <a href="https://github.com/zenitraM/malla">Malla</a></small>
<small>Powered by <a href="https://github.com/zenitraM/malla">Malla</a> v{{ APP_VERSION }}</small>
</div>
</div>
</div>
Expand Down
7 changes: 5 additions & 2 deletions src/malla/web_ui.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@

from flask import Flask

from . import get_version

# Import application configuration loader
from .config import AppConfig, get_config

Expand Down Expand Up @@ -220,6 +222,7 @@ def inject_config():
"APP_NAME": cfg.name,
"APP_CONFIG": cfg,
"DATABASE_FILE": cfg.database_file,
"APP_VERSION": get_version(),
}

# Initialize database
Expand All @@ -244,7 +247,7 @@ def health_check():
return {
"status": "healthy",
"service": "meshtastic-mesh-health-ui",
"version": "2.0.0",
"version": get_version(),
}

# Add application info
Expand All @@ -253,7 +256,7 @@ def app_info():
"""Application information endpoint."""
return {
"name": "Meshtastic Mesh Health Web UI",
"version": "2.0.0",
"version": get_version(),
"description": "Web interface for monitoring Meshtastic mesh network health",
"database_file": app.config["DATABASE_FILE"],
"components": {
Expand Down
24 changes: 22 additions & 2 deletions tests/integration/test_comprehensive_routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@

import pytest

from src.malla import get_version


class TestMainRoutes:
"""Test main application routes."""
Expand All @@ -23,6 +25,18 @@ def test_dashboard_route(self, client):
assert b"Total Nodes" in response.data
assert b"Active Nodes" in response.data

@pytest.mark.integration
def test_dashboard_shows_version(self, client):
"""Test that the dashboard displays the version in the footer."""
response = client.get("/")
assert response.status_code == 200
# Check that version appears in the footer
version = get_version()
assert version.encode() in response.data
# Check that "Malla" link appears (from footer)
assert b"Powered by" in response.data
assert b"Malla" in response.data

@pytest.mark.integration
def test_map_route(self, client):
"""Test the map view route."""
Expand Down Expand Up @@ -158,7 +172,10 @@ def test_health_endpoint(self, client):
data = response.get_json()
assert data["status"] == "healthy"
assert data["service"] == "meshtastic-mesh-health-ui"
assert data["version"] == "2.0.0"
# Verify version is present and matches the get_version() output
assert data["version"] == get_version()
# Version should be non-empty
assert len(data["version"]) > 0

@pytest.mark.integration
def test_info_endpoint(self, client):
Expand All @@ -168,7 +185,10 @@ def test_info_endpoint(self, client):

data = response.get_json()
assert data["name"] == "Meshtastic Mesh Health Web UI"
assert data["version"] == "2.0.0"
# Verify version is present and matches the get_version() output
assert data["version"] == get_version()
# Version should be non-empty
assert len(data["version"]) > 0
assert "components" in data
assert "database" in data["components"]

Expand Down
1 change: 0 additions & 1 deletion uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.