Commit Graph

74 Commits

Author SHA1 Message Date
Jorijn Schrijvershof
2a8c5dfdd9 ci: test docker builds on amd64, arm64, and armv7 in PRs 2026-01-13 07:06:03 +01:00
Jorijn Schrijvershof
0fc6ddfe3b build(docker): fix architecture support by adding UV_LIBC for ARM variants 2026-01-13 06:55:58 +01:00
Jorijn Schrijvershof
5efb81baf0 ci: test every architecture when making a change to the docker build 2026-01-13 06:51:40 +01:00
Jorijn Schrijvershof
8372fc5ef0 chore(main): release 0.2.14 (#63) v0.2.14 2026-01-13 06:44:41 +01:00
renovate[bot]
a89d745d6b chore(deps): lock file maintenance (#66)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-01-13 06:43:08 +01:00
renovate[bot]
63a842016c chore(deps): update golang docker tag to v1.25 (#70)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-01-13 06:40:33 +01:00
Jorijn Schrijvershof
75e50f7ee9 build(docker): add armv7 container support (#68)
* build(docker): add armv7 container support

* fix(docker): update base images and improve uv extraction process
2026-01-13 06:36:25 +01:00
renovate[bot]
c1b89782eb chore(deps): update github/codeql-action action to v4.31.10 (#67)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-01-12 22:23:23 +00:00
Jorijn Schrijvershof
b249a217e8 chore: add lockFileMaintenance to update types (#65) 2026-01-11 08:38:07 +01:00
renovate[bot]
18ca787f7f chore(deps): update ghcr.io/astral-sh/uv docker tag to v0.9.24 (#61)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-01-11 07:36:05 +00:00
Jorijn Schrijvershof
6fc2e762cf chore: enable renovate automerge for patch and digest updates (#64) 2026-01-11 08:30:29 +01:00
renovate[bot]
df0c374b65 chore(deps): update nginx:1.29-alpine docker digest to c083c37 (#62)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-01-11 08:16:01 +01:00
Jorijn Schrijvershof
570a086c8c chore(main): release 0.2.13 (#60) v0.2.13 2026-01-09 09:06:00 +01:00
Jorijn Schrijvershof
3a0306043c chore: drop digest from compose image (#59) 2026-01-09 09:04:27 +01:00
Jorijn Schrijvershof
1775c491ad chore(main): release 0.2.12 (#39) v0.2.12 2026-01-09 08:50:57 +01:00
renovate[bot]
a3a5964488 chore(deps): lock file maintenance (#58)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Jorijn Schrijvershof <jorijn@jorijn.com>
2026-01-09 08:49:10 +01:00
renovate[bot]
3967fd032a chore(deps): update actions/checkout action to v6 (#48)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-01-09 08:44:16 +01:00
renovate[bot]
97223f137c chore(deps): update actions/setup-python action to v6 (#49)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-01-09 08:34:04 +01:00
renovate[bot]
46fc383eaa chore(deps): update actions/upload-artifact action to v6 (#50)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-01-09 08:32:35 +01:00
renovate[bot]
f55c236080 chore(deps): pin python docker tag to e8a1ad8 (#57)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-01-09 08:31:04 +01:00
Jorijn Schrijvershof
b66f5380b6 chore: support python 3.14 in CI and docker (#56) 2026-01-09 08:29:13 +01:00
renovate[bot]
83425a48f6 chore(deps): update github/codeql-action action to v4 (#51)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-01-09 08:22:49 +01:00
renovate[bot]
9cb95f8108 chore(deps): pin dependencies (#55)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-01-09 08:20:27 +01:00
Jorijn Schrijvershof
1f6e7c5093 ci: switch actions to version tags for renovate digests (#54) 2026-01-09 08:18:02 +01:00
renovate[bot]
57a53a8800 chore(deps): update nginx docker tag to v1.29 (#47)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-01-09 08:09:23 +01:00
renovate[bot]
83cf2bf929 chore(deps): update ghcr.io/astral-sh/uv docker tag to v0.9.22 (#44)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-01-09 08:06:29 +01:00
Jorijn Schrijvershof
40d7d3b2fa ci(docker): add PR build and smoke test (#53) 2026-01-09 08:04:21 +01:00
renovate[bot]
d4b5885379 chore(deps): lock file maintenance (#52)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-01-09 08:01:13 +01:00
renovate[bot]
dd7ec5b46e chore(deps): update github/codeql-action digest to ee117c9 (#41)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-01-09 07:57:53 +01:00
renovate[bot]
e937f2b0b7 chore(deps): update actions/attest-build-provenance digest to 00014ed (#40)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-01-09 07:55:32 +01:00
Jorijn Schrijvershof
adc442351b chore: switch to Renovate and pin uv image (#38) 2026-01-09 07:51:00 +01:00
Jorijn Schrijvershof
3fa002d2a4 chore(main): release 0.2.11 (#34) v0.2.11 2026-01-08 21:53:13 +01:00
Jorijn Schrijvershof
26d5125e15 fix(docker): skip project install in uv sync (#35) 2026-01-08 21:51:14 +01:00
Jorijn Schrijvershof
fb627fdacd chore(release): track uv.lock in release-please (#33) 2026-01-08 21:46:34 +01:00
Jorijn Schrijvershof
62d72adf4e chore(main): release 0.2.10 (#28)
* chore(main): release 0.2.10

* chore(deps): refresh uv.lock
v0.2.10
2026-01-08 21:36:20 +01:00
Jorijn Schrijvershof
ca13e31aae test: stabilize suite and broaden integration coverage (#32)
* tests: cache integration/report fixtures to speed up tests

* fix: speed up yearly aggregation and refresh timings report

* chore: remove the report

* fix: unrecognized named-value: 'runner'. Located at position 1 within expression: runner.temp

* fix: ruff linting error

* test: strengthen assertions and stabilize tests

* test(integration): expand rendered chart metrics
2026-01-08 21:20:34 +01:00
Jorijn Schrijvershof
a9f6926104 test: add comprehensive pytest test suite with 95% coverage (#29)
* test: add comprehensive pytest test suite with 95% coverage

Add full unit and integration test coverage for the meshcore-stats project:

- 1020 tests covering all modules (db, charts, html, reports, client, etc.)
- 95.95% code coverage with pytest-cov (95% threshold enforced)
- GitHub Actions CI workflow for automated testing on push/PR
- Proper mocking of external dependencies (meshcore, serial, filesystem)
- SVG snapshot infrastructure for chart regression testing
- Integration tests for collection and rendering pipelines

Test organization:
- tests/charts/: Chart rendering and statistics
- tests/client/: MeshCore client and connection handling
- tests/config/: Environment and configuration parsing
- tests/database/: SQLite operations and migrations
- tests/html/: HTML generation and Jinja templates
- tests/reports/: Report generation and formatting
- tests/retry/: Circuit breaker and retry logic
- tests/unit/: Pure unit tests for utilities
- tests/integration/: End-to-end pipeline tests

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* chore: add test-engineer agent configuration

Add project-local test-engineer agent for pytest test development,
coverage analysis, and test review tasks.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* docs: comprehensive test suite review with 956 tests analyzed

Conducted thorough review of all 956 test cases across 47 test files:

- Unit Tests: 338 tests (battery, metrics, log, telemetry, env, charts, html, reports, formatters)
- Config Tests: 53 tests (env loading, config file parsing)
- Database Tests: 115 tests (init, insert, queries, migrations, maintenance, validation)
- Retry Tests: 59 tests (circuit breaker, async retries, factory)
- Charts Tests: 76 tests (transforms, statistics, timeseries, rendering, I/O)
- HTML Tests: 81 tests (site generation, Jinja2, metrics builders, reports index)
- Reports Tests: 149 tests (location, JSON/TXT formatting, aggregation, counter totals)
- Client Tests: 63 tests (contacts, connection, meshcore availability, commands)
- Integration Tests: 22 tests (reports, collection, rendering pipelines)

Results:
- Overall Pass Rate: 99.7% (953/956)
- 3 tests marked for improvement (empty test bodies in client tests)
- 0 tests requiring fixes

Key findings documented in test_review/tests.md including quality
observations, F.I.R.S.T. principle adherence, and recommendations.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* test: implement snapshot testing for charts and reports

Add comprehensive snapshot testing infrastructure:

SVG Chart Snapshots:
- Deterministic fixtures with fixed timestamps (2024-01-15 12:00:00)
- Tests for gauge/counter metrics in light/dark themes
- Empty chart and single-point edge cases
- Extended normalize_svg_for_snapshot_full() for reproducible comparisons

TXT Report Snapshots:
- Monthly/yearly report snapshots for repeater and companion
- Empty report handling tests
- Tests in tests/reports/test_snapshots.py

Infrastructure:
- tests/snapshots/conftest.py with shared fixtures
- UPDATE_SNAPSHOTS=1 environment variable for regeneration
- scripts/generate_snapshots.py for batch snapshot generation

Run `UPDATE_SNAPSHOTS=1 pytest tests/charts/test_chart_render.py::TestSvgSnapshots`
to generate initial snapshots.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* test: fix SVG normalization and generate initial snapshots

Fix normalize_svg_for_snapshot() to handle:
- clipPath IDs like id="p47c77a2a6e"
- url(#p...) references
- xlink:href="#p..." references
- <dc:date> timestamps

Generated initial snapshot files:
- 7 SVG chart snapshots (gauge, counter, empty, single-point in light/dark)
- 6 TXT report snapshots (monthly/yearly for repeater/companion + empty)

All 13 snapshot tests now pass.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* test: fix SVG normalization to preserve axis rendering

The SVG normalization was replacing all matplotlib-generated IDs with
the same value, causing duplicate IDs that broke SVG rendering:
- Font glyphs, clipPaths, and tick marks all got id="normalized"
- References couldn't resolve to the correct elements
- X and Y axes failed to render in normalized snapshots

Fix uses type-specific prefixes with sequential numbering:
- glyph_N for font glyphs (DejaVuSans-XX patterns)
- clip_N for clipPath definitions (p[0-9a-f]{8,} patterns)
- tick_N for tick marks (m[0-9a-f]{8,} patterns)

This ensures all IDs remain unique while still being deterministic
for snapshot comparison.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* chore: add coverage and pytest artifacts to gitignore

Add .coverage, .coverage.*, htmlcov/, and .pytest_cache/ to prevent
test artifacts from being committed.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* style: fix all ruff lint errors across codebase

- Sort and organize imports (I001)
- Use modern type annotations (X | Y instead of Union, collections.abc)
- Remove unused imports (F401)
- Combine nested if statements (SIM102)
- Use ternary operators where appropriate (SIM108)
- Combine nested with statements (SIM117)
- Use contextlib.suppress instead of try-except-pass (SIM105)
- Add noqa comments for intentional SIM115 violations (file locks)
- Add TYPE_CHECKING import for forward references
- Fix exception chaining (B904)

All 1033 tests pass.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* docs: add TDD workflow and pre-commit requirements to CLAUDE.md

- Add mandatory test-driven development workflow (write tests first)
- Add pre-commit requirements (must run lint and tests before committing)
- Document test organization and running commands
- Document 95% coverage requirement

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix: resolve mypy type checking errors with proper structural fixes

- charts.py: Create PeriodConfig dataclass for type-safe period configuration,
  use mdates.date2num() for matplotlib datetime handling, fix x-axis limits
  for single-point charts
- db.py: Add explicit int() conversion with None handling for SQLite returns
- env.py: Add class-level type annotations to Config class
- html.py: Add MetricDisplay TypedDict, fix import order, add proper type
  annotations for table data functions
- meshcore_client.py: Add return type annotation

Update tests to use new dataclass attribute access and regenerate SVG
snapshots. Add mypy step to CLAUDE.md pre-commit requirements.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix: cast Jinja2 template.render() to str for mypy

Jinja2's type stubs declare render() as returning Any, but it actually
returns str. Wrap with str() to satisfy mypy's no-any-return check.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* ci: improve workflow security and reliability

- test.yml: Pin all actions by SHA, add concurrency control to cancel
  in-progress runs on rapid pushes
- release-please.yml: Pin action by SHA, add 10-minute timeout
- conftest.py: Fix snapshot_base_time to use explicit UTC timezone for
  consistent behavior across CI and local environments

Regenerate SVG snapshots with UTC-aware timestamps.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix: add mypy command to permissions in settings.local.json

* test: add comprehensive script tests with coroutine warning fixes

- Add tests/scripts/ with tests for collect_companion, collect_repeater,
  and render scripts (1135 tests total, 96% coverage)
- Fix unawaited coroutine warnings by using AsyncMock properly for async
  functions and async_context_manager_factory fixture for context managers
- Add --cov=scripts to CI workflow and pyproject.toml coverage config
- Omit scripts/generate_snapshots.py from coverage (dev utility)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* docs: migrate claude setup to codex skills

* feat: migrate dependencies to uv (#31)

* fix: run tests through uv

* test: fix ruff lint issues in tests

Consolidate patch context managers and clean unused imports/variables

Use datetime.UTC in snapshot fixtures

* test: avoid unawaited async mocks in entrypoint tests

* ci: replace codecov with github coverage artifacts

Add junit XML output and coverage summary in job output

Upload HTML and XML coverage artifacts (3.12 only) on every run

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-08 17:16:53 +01:00
Jorijn Schrijvershof
45bdf5d6d4 docs: add TZ timezone setting to example config
Documents how to set timezone for Docker deployments to ensure
chart X-axis labels and timestamps display in local time.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-06 17:17:20 +01:00
Jorijn Schrijvershof
c199ace4a2 chore(main): release 0.2.9 (#27) v0.2.9 2026-01-06 13:57:15 +01:00
Jorijn Schrijvershof
f7923b9434 fix: tooltip positioning and locale-aware time formatting
- Fix tooltip indicator dot appearing above chart line by using
  clipPath rect bounds instead of line path bounding box for Y positioning
- Inject data-points attribute into line path inside #chart-line group
- Refactor chart-tooltip.js with clear sections, extracted utilities,
  and centralized configuration
- Use navigator.language for date formatting to respect browser
  language preference (fixes 12h/24h format based on locale)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-06 13:56:36 +01:00
Jorijn Schrijvershof
c978844271 ci: add artifact-metadata permission for attestation storage records
Fixes warning: "Failed to create storage record: artifact-metadata:write
permission has been included"

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-06 12:15:50 +01:00
Jorijn Schrijvershof
64cc352b80 chore(main): release 0.2.8 (#26) v0.2.8 2026-01-06 12:06:53 +01:00
Jorijn Schrijvershof
e37aef6c5e fix: normalize reporting outputs and chart tooltips
- render last observation with local TZ label

- show zero values in report tables

- keep report JSON raw values with explicit units

- reduce chart queries per period and tag chart line paths

- remove redundant get_bat call in companion collector
2026-01-06 11:24:47 +01:00
Jorijn Schrijvershof
81b7c6897a chore(main): release 0.2.7 (#25) v0.2.7 2026-01-06 09:54:44 +01:00
Jorijn Schrijvershof
a3015e2209 feat: add telemetry collection for companion and repeater nodes (#24)
Add environmental telemetry collection (temperature, humidity, barometric
pressure, voltage) from both the repeater node (over LoRa) and companion
node (local serial). Telemetry is stored in the same EAV metrics table
with `telemetry.` prefix.

Key changes:
- Add TELEMETRY_ENABLED feature flag (defaults to OFF)
- Add telemetry-specific timeout/retry settings
- Create shared telemetry.py module with extract_lpp_from_payload()
  and extract_telemetry_metrics() helpers
- Handle MeshCore API dict payload format: {'pubkey_pre': '...', 'lpp': [...]}
- Repeater: store status metrics BEFORE attempting telemetry (LoRa reliability)
- Companion: merge telemetry into single DB write (serial is reliable)
- Telemetry failures do NOT affect circuit breaker state

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-06 09:53:15 +01:00
Jorijn Schrijvershof
5545ce5b28 Merge pull request #23 from jorijn/release-please--branches--main--components--meshcore-stats
chore(main): release 0.2.6
v0.2.6
2026-01-05 10:50:13 +01:00
Jorijn Schrijvershof
666ed4215f chore(main): release 0.2.6 2026-01-05 10:49:22 +01:00
Jorijn Schrijvershof
3d0d90304c fix: add tmpfs mount for fontconfig cache to fix read-only filesystem errors
The container runs with read_only: true for security hardening, but
fontconfig needs a writable cache directory. Added tmpfs mount at
/var/cache/fontconfig to allow fontconfig to write its cache without
compromising the read-only filesystem security.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-05 10:49:02 +01:00
Jorijn Schrijvershof
6afc14e007 Merge pull request #21 from jorijn/release-please--branches--main--components--meshcore-stats
chore(main): release 0.2.5
v0.2.5
2026-01-05 10:03:26 +01:00
Jorijn Schrijvershof
4c5a408604 chore(main): release 0.2.5 2026-01-05 10:00:46 +01:00