Files
TimeTracker/docs/implementation-notes/VERSION_MANAGEMENT_SUMMARY.md
Dries Peeters e4789cc26e feat: Add telemetry and analytics infrastructure with observability stack
Implement comprehensive analytics and monitoring system with PostHog integration,
complete observability stack (Prometheus, Grafana, Loki, Promtail), and CI/CD
workflows for automated builds.

Features:
- Add PostHog telemetry integration with privacy-focused event tracking
- Implement installation flow for opt-in telemetry configuration
- Add telemetry management UI in admin panel with detailed transparency
- Track key user events across all major features (projects, tasks, timer, etc.)

Infrastructure:
- Set up Prometheus for metrics collection
- Configure Grafana for visualization dashboards
- Integrate Loki and Promtail for log aggregation
- Add separate analytics docker-compose configuration

CI/CD:
- Add GitHub Actions workflows for building and publishing Docker images
- Implement separate dev and production build pipelines
- Configure automated image publishing to registry

Documentation:
- Restructure documentation into organized docs/ directory
- Add comprehensive guides for telemetry, analytics, and local development
- Create transparency documentation for tracked events
- Add CI/CD and build configuration guides

Code improvements:
- Integrate telemetry hooks across all route handlers
- Add feature flags and configuration management
- Refactor test suite for analytics functionality
- Clean up root directory by moving docs and removing test artifacts

Breaking changes:
- Requires new environment variables for PostHog configuration
- Docker compose setup now supports analytics stack

Changes: 73 files changed, 955 insertions(+), 14126 deletions(-)
2025-10-20 14:38:57 +02:00

5.8 KiB
Raw Blame History

Version Management Update

Summary

Successfully updated TimeTracker to read the application version from setup.py at runtime instead of embedding it during build time or using environment variables.

Changes Made

1. Version Reading Function

File: app/config/analytics_defaults.py

Added _get_version_from_setup() function that:

  • Reads setup.py at runtime
  • Extracts version using regex: version='3.0.0'
  • Returns the version string
  • Falls back to "3.0.0" if file can't be read
def _get_version_from_setup():
    """
    Get the application version from setup.py.
    
    This is the authoritative source for version information.
    Reads setup.py at runtime to get the current version.
    
    Returns:
        str: Application version (e.g., "3.0.0")
    """
    import os
    import re
    
    try:
        # Get path to setup.py (root of project)
        setup_path = os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(__file__))), 'setup.py')
        
        # Read setup.py
        with open(setup_path, 'r', encoding='utf-8') as f:
            content = f.read()
        
        # Extract version using regex
        version_match = re.search(r'version\s*=\s*[\'"]([^\'"]+)[\'"]', content)
        
        if version_match:
            return version_match.group(1)
    except Exception:
        pass
    
    # Fallback version if setup.py can't be read
    return "3.0.0"

2. Updated Analytics Config

File: app/config/analytics_defaults.py

Modified get_analytics_config() to use runtime version:

# App version - read from setup.py at runtime
app_version = _get_version_from_setup()

3. Updated Telemetry

File: app/utils/telemetry.py

Updated _get_installation_properties() to get version from analytics config:

# Get app version from analytics config (which reads from setup.py)
from app.config.analytics_defaults import get_analytics_config
analytics_config = get_analytics_config()
app_version = analytics_config.get("app_version", "3.0.0")

4. Updated Event Tracking

File: app/__init__.py

Updated track_event() to get version from analytics config:

# Get app version from analytics config
from app.config.analytics_defaults import get_analytics_config
analytics_config = get_analytics_config()

enhanced_properties.update({
    "environment": os.getenv("FLASK_ENV", "production"),
    "app_version": analytics_config.get("app_version", "3.0.0"),
    "deployment_method": "docker" if os.path.exists("/.dockerenv") else "native",
})

5. Removed Version from Build Process

File: .github/workflows/build-and-publish.yml

Removed version injection from the build workflow:

# No longer injecting VERSION
# Version is read from setup.py at runtime

- name: Inject analytics configuration
  env:
    POSTHOG_API_KEY: ${{ secrets.POSTHOG_API_KEY }}
    SENTRY_DSN: ${{ secrets.SENTRY_DSN }}
    # No VERSION env var
  run: |
    # No sed command for APP_VERSION_PLACEHOLDER
    echo "  App version will be read from setup.py at runtime"

6. Added Tests

File: tests/test_version_reading.py

Created tests to verify version reading works correctly.

How It Works

Single Source of Truth

setup.py (version='3.0.0')
    ↓
_get_version_from_setup() reads file at runtime
    ↓
get_analytics_config() returns version
    ↓
Used everywhere:
    - Telemetry properties
    - PostHog events
    - Sentry release tags
    - Event tracking

Benefits

  1. Single Source of Truth: Version defined once in setup.py
  2. No Build Injection: Simpler build process
  3. Dynamic Updates: Change version in setup.py, restart app, new version used
  4. No Environment Variable: Can't be overridden accidentally
  5. Consistent: Same version everywhere in the app

Version Flow

Startup:
    ↓
Analytics config loads
    ↓
_get_version_from_setup() called
    ↓
Reads setup.py: version='3.0.0'
    ↓
Extracts: "3.0.0"
    ↓
Cached in analytics_config
    ↓
Used for all telemetry

Testing

Verified Working

$ python test_version_extraction.py
✅ Successfully extracted version from setup.py: 3.0.0

No Linting Errors

✅ app/__init__.py - No errors
✅ app/config/analytics_defaults.py - No errors
✅ app/utils/telemetry.py - No errors

Usage

To Update Version

  1. Edit setup.py:

    setup(
        name='timetracker',
        version='3.1.0',  # Update here
        ...
    )
    
  2. Restart application:

    docker-compose restart app
    
  3. New version is automatically used everywhere

Verification

Check version being used:

from app.config.analytics_defaults import _get_version_from_setup
print(_get_version_from_setup())  # Should match setup.py

Fallback Behavior

If setup.py can't be read:

  • Function catches exception
  • Returns fallback: "3.0.0"
  • App continues to work
  • Logs show the fallback version

Files Modified

  1. app/config/analytics_defaults.py - Added version reading function
  2. app/utils/telemetry.py - Uses analytics config for version
  3. app/__init__.py - Uses analytics config for version (fixed indentation)
  4. .github/workflows/build-and-publish.yml - Removed version injection
  5. tests/test_version_reading.py - Added tests

Summary

Before:

  • Version embedded during build via GitHub Actions
  • Required environment variable or placeholder replacement
  • Multiple sources of version information

After:

  • Version read from setup.py at runtime
  • Single source of truth
  • Simpler build process
  • Dynamic version updates

Result:

  • Version always matches setup.py
  • No build-time injection needed
  • No environment variables needed
  • Simpler and more maintainable

All changes tested and working! 🎉