diff --git a/Dockerfile.cron b/Dockerfile.cron new file mode 100644 index 0000000..b75fcf4 --- /dev/null +++ b/Dockerfile.cron @@ -0,0 +1,23 @@ +FROM --platform=$TARGETPLATFORM python:3.12-slim-bookworm + +ENV PYTHONDONTWRITEBYTECODE=1 \ + PYTHONUNBUFFERED=1 \ + PIP_NO_CACHE_DIR=1 + +WORKDIR /app + +# Install Python dependencies first to leverage layer caching. +COPY requirements.txt ./ +RUN pip install --no-cache-dir -r requirements.txt + +# Copy application source. +COPY jira_jotty_sync.py ./ +COPY sync_config.json.template ./ + +# Run as non-root for better container security. +RUN useradd --create-home --uid 10001 appuser && chown -R appuser:appuser /app +USER appuser + +# Run every 5 minutes via cron +CMD echo "*/5 * * * * cd /app && python jira_jotty_sync.py --direction both >> /tmp/sync.log 2>&1" | crontab - && \ + crond -f diff --git a/jira_jotty_sync.py b/jira_jotty_sync.py index 8823cc0..79e6e39 100644 --- a/jira_jotty_sync.py +++ b/jira_jotty_sync.py @@ -14,11 +14,54 @@ Usage: Configuration is stored in sync_config.json (see template below). """ +import os +import subprocess +import sys + +# --------------------------------------------------------------------------- +# Auto-venv setup: if not running inside a virtual environment, create one, +# install requirements, and re-execute this script with the venv Python. +# --------------------------------------------------------------------------- +def _ensure_venv(): + """Create .venv if missing, install requirements, then re-execute self.""" + # Check if we're already in a venv + in_venv = getattr(sys, "prefix", None) != getattr(sys, "base_prefix", None) + if in_venv: + return + + script_dir = os.path.dirname(os.path.abspath(__file__)) + venv_path = os.path.join(script_dir, ".venv") + requirements_file = os.path.join(script_dir, "requirements.txt") + + # Create virtual environment if it doesn't exist + if not os.path.isdir(venv_path): + print(f"[setup] Creating virtual environment in {venv_path} ...") + subprocess.run([sys.executable, "-m", "venv", venv_path], check=True) + + # Determine the venv python executable (cross-platform) + if os.name == "nt": # Windows + venv_python = os.path.join(venv_path, "Scripts", "python.exe") + else: + venv_python = os.path.join(venv_path, "bin", "python") + + # Install requirements if not already installed + print(f"[setup] Installing dependencies ...") + subprocess.run( + [venv_python, "-m", "pip", "install", "--upgrade", "-r", requirements_file], + check=True, + ) + + # Re-execute this script using the venv Python + print("[setup] Relaunching with virtual environment ...") + sys.exit(subprocess.call([venv_python, __file__] + sys.argv[1:])) + + +_ensure_venv() +del _ensure_venv # Clean up namespace + import argparse import json import logging -import os -import sys import time from dataclasses import dataclass, field from typing import Optional