Skip to content

Use git tags for versioning via setuptools-scm - #47

Merged
dk307 merged 5 commits into
mainfrom
deploy_fix
Aug 2, 2026
Merged

Use git tags for versioning via setuptools-scm#47
dk307 merged 5 commits into
mainfrom
deploy_fix

Conversation

@dk307

@dk307 dk307 commented Aug 2, 2026

Copy link
Copy Markdown
Owner

Summary by CodeRabbit

  • New Features
    • Improved live camera stream lifecycle handling, including automatic startup and idle shutdown of streaming services.
    • Dashboard status updates now pause when scans, downloads, or purge operations are idle.
  • Build and Packaging
    • Improved application version handling during builds.
    • Added a fallback version for environments without source-control metadata.
    • Build artifacts can now reflect the specified application version automatically.

@coderabbitai

coderabbitai Bot commented Aug 2, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@dk307, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 17 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: e13d985f-061d-4d4a-8771-bc04c18fe84e

📥 Commits

Reviewing files that changed from the base of the PR and between 9ded7aa and a0e1087.

📒 Files selected for processing (6)
  • .github/workflows/ci.yml
  • app/api/cameras.py
  • app/services/go2rtc.py
  • frontend/src/pages/Dashboard.test.tsx
  • tests/integration/test_cameras_api.py
  • tests/unit/test_go2rtc.py
📝 Walkthrough

Walkthrough

The project now uses dynamic SCM-based versioning with a fallback. Docker builds pass the generated version to the runtime. go2rtc starts on demand and stops after stream inactivity. Dashboard polling stops when operations are idle.

Changes

Dynamic versioning

Layer / File(s) Summary
SCM version configuration
pyproject.toml, .github/workflows/ci.yml
The static project version is replaced with dynamic resolution. setuptools-scm>=8 and a fallback version are configured. Release version updates now target frontend/package.json.
Build version wiring
.github/workflows/ci.yml, docker/Dockerfile
E2E and release Docker builds pass application version, Git SHA, and build time. The runtime exposes APP_VERSION through SETUPTOOLS_SCM_PRETEND_VERSION.

go2rtc stream lifecycle

Layer / File(s) Summary
Stream activity control
app/services/go2rtc.py
go2rtc tracks active streams, starts when a stream begins, and schedules shutdown after 60 seconds with no active streams.
WebSocket lifecycle wiring
app/api/cameras.py, tests/integration/test_cameras_api.py
The camera WebSocket reports stream start and stream end events to go2rtc. The integration test verifies one callback for each event.
Application shutdown behavior
app/main.py, tests/unit/test_main.py
Application startup no longer starts go2rtc. Application shutdown still stops go2rtc.
Stream lifecycle validation
tests/unit/test_go2rtc.py
Unit tests cover active-stream counts, process reuse, idle timers, timer cancellation, and shutdown reset behavior.

Conditional dashboard polling

Layer / File(s) Summary
Conditional status polling
frontend/src/pages/Dashboard.tsx, frontend/src/pages/Dashboard.test.tsx
Scanner, bulk download, and bulk purge queries poll unresolved or active operations every three seconds and stop polling after idle responses.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant CameraWebSocket
  participant cameras_proxy
  participant go2rtc_service
  participant go2rtc_process

  CameraWebSocket->>cameras_proxy: Open live stream
  cameras_proxy->>go2rtc_service: stream_started()
  go2rtc_service->>go2rtc_process: Start or reuse process
  CameraWebSocket->>cameras_proxy: Close live stream
  cameras_proxy->>go2rtc_service: stream_ended()
  go2rtc_service->>go2rtc_process: Schedule idle shutdown
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 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 describes the setuptools-scm and Git tag versioning changes in the pull request.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch deploy_fix

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.

@github-actions

github-actions Bot commented Aug 2, 2026

Copy link
Copy Markdown

Coverage

Coverage Report
FileStmtsMissCoverMissing
__init__.py00100% 
build_info.py50100% 
config.py240100% 
database.py23196%39
main.py821384%49–50, 58, 133–135, 137–142, 144
api
   __init__.py00100% 
   activity.py240100% 
   app_settings.py270100% 
   cameras.py3721696%233, 235, 237, 241, 523–526, 534–537, 541, 580, 612–613
   health.py34391%17–19
   locations.py380100% 
   logs.py280100% 
   recordings.py142199%88
   scanner.py280100% 
   storage.py60100% 
   system_info.py137199%33
   timeline.py290100% 
models
   __init__.py00100% 
   app_settings.py130100% 
   base.py80100% 
   camera.py320100% 
   download_event.py140100% 
   location.py90100% 
   purge_event.py140100% 
   recording.py38197%56
   scan_event.py140100% 
schemas
   __init__.py00100% 
   app_settings.py60100% 
   camera.py990100% 
   location.py110100% 
   recording.py80100% 
services
   __init__.py00100% 
   downloader.py156299%324–325
   go2rtc.py213199%178
   hikvision.py175299%154–155
   log_buffer.py63297%77–78
   purger.py1400100% 
   reconcile.py170100% 
   scanner.py273399%341, 367, 429
   storage.py220100% 
   tz.py540100% 
workers
   __init__.py00100% 
   scheduler.py1230100% 
TOTAL25014698% 

@codecov

codecov Bot commented Aug 2, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 98.41270% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 93.01%. Comparing base (c845089) to head (a0e1087).

Files with missing lines Patch % Lines
app/services/go2rtc.py 97.91% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main      #47      +/-   ##
==========================================
+ Coverage   92.97%   93.01%   +0.03%     
==========================================
  Files          81       81              
  Lines        7191     7239      +48     
  Branches      718      724       +6     
==========================================
+ Hits         6686     6733      +47     
- Misses        472      473       +1     
  Partials       33       33              
Flag Coverage Δ
backend 98.16% <98.03%> (-0.02%) ⬇️
frontend 90.29% <100.00%> (+0.01%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

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)
docker/Dockerfile (1)

39-40: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win

Scope the pretend-version override to camera-event-manager.

SETUPTOOLS_SCM_PRETEND_VERSION is global, and it is set before pip install ".[prod]". Source-built dependencies that also use setuptools-scm can inherit the APP_VERSION value as their own version. Use SETUPTOOLS_SCM_PRETEND_VERSION_FOR_CAMERA_EVENT_MANAGER for this distribution, or unset the global env var before installing dependencies.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docker/Dockerfile` around lines 39 - 40, Update the Dockerfile environment
setup around APP_VERSION so the setuptools-scm pretend-version override is
scoped specifically to camera-event-manager, using the distribution-specific
variable rather than global SETUPTOOLS_SCM_PRETEND_VERSION before pip install.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docker/Dockerfile`:
- Around line 39-40: Update the APP_VERSION default near the Dockerfile’s
SETUPTOOLS_SCM_PRETEND_VERSION assignment to a valid PEP 440 version, preferably
0.0.0, so the image build does not override pyproject.toml’s fallback with
“unknown”.

---

Nitpick comments:
In `@docker/Dockerfile`:
- Around line 39-40: Update the Dockerfile environment setup around APP_VERSION
so the setuptools-scm pretend-version override is scoped specifically to
camera-event-manager, using the distribution-specific variable rather than
global SETUPTOOLS_SCM_PRETEND_VERSION before pip install.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: eafabe52-69d8-4795-9eb7-11ed1bde903c

📥 Commits

Reviewing files that changed from the base of the PR and between c845089 and 890d43a.

📒 Files selected for processing (2)
  • docker/Dockerfile
  • pyproject.toml

Comment thread docker/Dockerfile Outdated
dk307 added 2 commits August 1, 2026 22:27
…y-starting go2rtc

- Dashboard: dynamic refetchInterval stops polling when no operations running
- go2rtc: lazy-start (removed from lifespan) + idle-stop after 60s with no streams
- Wire stream_started/stream_ended lifecycle in WS proxy
- Add comprehensive tests for all new behavior

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
app/api/cameras.py (1)

563-608: 🩺 Stability & Availability | 🔴 Critical | ⚡ Quick win

Call go2rtc.stream_started() inside the try block to avoid leaking the session and the stream counter.

go2rtc.stream_started() runs at Line 564, before the try block starts at Line 565. If stream_started() raises, the exception skips the finally block entirely. start()'s call to _write_config() sits outside start()'s own try/except OSError, so a file-write failure there propagates all the way up through stream_started().

Two things leak in that case:

  • session (created at Line 563) never reaches session.close() at Line 608, leaking the aiohttp.ClientSession.
  • go2rtc.stream_ended() at Line 607 never runs, so _active_streams stays incremented forever and the idle-stop timer never fires for this stream.

Move go2rtc.stream_started() inside the try block so finally always closes the session and always calls stream_ended(), keeping the counter balanced regardless of how stream_started() behaves.

🐛 Proposed fix
     session = aiohttp.ClientSession()
-    go2rtc.stream_started()
     try:
+        go2rtc.stream_started()
         async with session.ws_connect(upstream_url) as upstream:
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/api/cameras.py` around lines 563 - 608, Move go2rtc.stream_started() from
before the try statement into the beginning of that try block, while keeping
session creation before it. Preserve the existing finally block so
session.close() and go2rtc.stream_ended() execute whenever stream_started()
raises or the proxy flow fails.
🧹 Nitpick comments (2)
tests/unit/test_go2rtc.py (1)

493-515: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add a direct test for _idle_stop()'s termination path.

Current tests cover stream_started(), stream_ended(), and timer scheduling, but no test calls _idle_stop() directly. Add a test that sets _active_streams = 0, sets _proc to a fake process, calls go2rtc._idle_stop() directly, and asserts fake.terminate() runs and go2rtc._proc becomes None. Add a second test for the zombie-reap branch, similar to test_stop_kills_process_that_ignores_terminate at Lines 135-145.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/unit/test_go2rtc.py` around lines 493 - 515, Add direct coverage for
go2rtc._idle_stop(): with _active_streams set to zero and a fake _proc, assert
the normal termination path calls terminate() and clears _proc. Add a second
test covering the zombie-reap path, mirroring the process behavior and
assertions in test_stop_kills_process_that_ignores_terminate.
tests/integration/test_cameras_api.py (1)

814-830: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add a regression test for the leak when stream_started() raises.

This test confirms stream_started() and stream_ended() each run once on a normal connection. Add a test where app.services.go2rtc.stream_started raises, then assert app.services.go2rtc.stream_ended still runs and the fake session's close() still runs. Against the current app/api/cameras.py code, this test fails because stream_started() runs outside the try block. This test will confirm the fix once stream_started() moves inside the try block.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/integration/test_cameras_api.py` around lines 814 - 830, Add a
regression test alongside test_live_ws_calls_stream_lifecycle where
go2rtc.stream_started raises, then assert the exception path still invokes
go2rtc.stream_ended exactly once and the fake aiohttp session’s close() exactly
once. Configure the existing _fake_session_cls and websocket setup to observe
close(), preserving the normal lifecycle test unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/ci.yml:
- Around line 153-156: Update the E2E build’s BUILD_TIME argument in the
workflow build-args block to use a timestamp available during pull_request runs,
such as checkout metadata or github.run_started_at, instead of
github.event.head_commit.timestamp; preserve the existing APP_VERSION and
GIT_SHA arguments.

In `@app/services/go2rtc.py`:
- Around line 154-180: Extract the duplicated terminate/kill/reap sequence into
a shared _terminate_and_reap() helper. Update both stop() and _idle_stop() to
acquire _lock only long enough to swap _proc to None, then perform the blocking
process termination and waits outside the lock; preserve the existing
graceful-terminate, timeout-kill, and unreaped-process warning behavior.

In `@frontend/src/pages/Dashboard.test.tsx`:
- Around line 193-196: Update the initial counter setup in the Dashboard test to
wait until the scanner, download, and purge status request counters have each
reached their expected initial values before assigning initialScan, initialDl,
and initialPurge. Keep the existing counter snapshots unchanged after this
combined wait.

---

Outside diff comments:
In `@app/api/cameras.py`:
- Around line 563-608: Move go2rtc.stream_started() from before the try
statement into the beginning of that try block, while keeping session creation
before it. Preserve the existing finally block so session.close() and
go2rtc.stream_ended() execute whenever stream_started() raises or the proxy flow
fails.

---

Nitpick comments:
In `@tests/integration/test_cameras_api.py`:
- Around line 814-830: Add a regression test alongside
test_live_ws_calls_stream_lifecycle where go2rtc.stream_started raises, then
assert the exception path still invokes go2rtc.stream_ended exactly once and the
fake aiohttp session’s close() exactly once. Configure the existing
_fake_session_cls and websocket setup to observe close(), preserving the normal
lifecycle test unchanged.

In `@tests/unit/test_go2rtc.py`:
- Around line 493-515: Add direct coverage for go2rtc._idle_stop(): with
_active_streams set to zero and a fake _proc, assert the normal termination path
calls terminate() and clears _proc. Add a second test covering the zombie-reap
path, mirroring the process behavior and assertions in
test_stop_kills_process_that_ignores_terminate.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 88954b38-3fce-4ce5-9095-4e4797a2c977

📥 Commits

Reviewing files that changed from the base of the PR and between 890d43a and 9ded7aa.

📒 Files selected for processing (10)
  • .github/workflows/ci.yml
  • app/api/cameras.py
  • app/main.py
  • app/services/go2rtc.py
  • docker/Dockerfile
  • frontend/src/pages/Dashboard.test.tsx
  • frontend/src/pages/Dashboard.tsx
  • tests/integration/test_cameras_api.py
  • tests/unit/test_go2rtc.py
  • tests/unit/test_main.py
💤 Files with no reviewable changes (1)
  • app/main.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • docker/Dockerfile

Comment thread .github/workflows/ci.yml Outdated
Comment thread app/services/go2rtc.py
Comment thread frontend/src/pages/Dashboard.test.tsx Outdated
dk307 added 2 commits August 2, 2026 11:29
camera_streams endpoint now calls go2rtc.start() before checking
availability, ensuring go2rtc is launched on-demand when a user
visits a camera's live view (E2E test fix).
- ci.yml: use github.run_started_at for BUILD_TIME (available in all event types)
- go2rtc.py: extract _terminate_and_reap() helper, release _lock before blocking waits
- cameras.py: move stream_started() inside try block for proper cleanup on error
- Dashboard.test.tsx: wait for all three counters before snapshotting initial values
- Add test for stream_started() error still calling stream_ended/session.close
- Add _idle_stop() unit tests (normal terminate + zombie-reap paths)
@dk307
dk307 merged commit dc2f6c8 into main Aug 2, 2026
9 checks passed
@dk307
dk307 deleted the deploy_fix branch August 2, 2026 19:09
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