From 53e4d54d14a73292e2e62d1277a7935070f853d1 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 25 May 2025 21:06:33 +0000 Subject: [PATCH 1/2] Initial plan for issue From f547e9d7297e88419653ddedeba8a46d2a75cb69 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 25 May 2025 21:13:52 +0000 Subject: [PATCH 2/2] Add template dependency group and sync workflow Co-authored-by: lucasrcezimbra <7042915+lucasrcezimbra@users.noreply.github.com> --- .github/scripts/sync_dependencies.py | 61 +++++++++++++++++++++++++ .github/workflows/sync-dependencies.yml | 49 ++++++++++++++++++++ README.md | 13 ++++++ pyproject.toml | 22 +++++++++ 4 files changed, 145 insertions(+) create mode 100755 .github/scripts/sync_dependencies.py create mode 100644 .github/workflows/sync-dependencies.yml diff --git a/.github/scripts/sync_dependencies.py b/.github/scripts/sync_dependencies.py new file mode 100755 index 0000000..5f5d3c5 --- /dev/null +++ b/.github/scripts/sync_dependencies.py @@ -0,0 +1,61 @@ +#!/usr/bin/env python3 +""" +Script to sync dependencies between the root pyproject.toml and the template pyproject.toml. +This script reads the dependencies from the template group in the root pyproject.toml +and updates the corresponding dependencies in the template pyproject.toml. +""" + +import re +import tomlkit + + +def read_toml_file(file_path): + """Read a TOML file and return its content as a dictionary.""" + with open(file_path, 'r') as f: + return tomlkit.parse(f.read()) + + +def update_template_pyproject(): + """Update the template pyproject.toml with dependencies from the root pyproject.toml.""" + # Read the root pyproject.toml + root_pyproject = read_toml_file("pyproject.toml") + + # Read the template pyproject.toml as text to preserve templating + with open("{{cookiecutter.project_slug}}/pyproject.toml", 'r') as f: + template_content = f.read() + + # Extract dependencies from the root pyproject.toml template group + template_deps = root_pyproject.get("tool", {}).get("poetry", {}).get("group", {}).get("template", {}).get("dependencies", {}) + template_dev_deps = root_pyproject.get("tool", {}).get("poetry", {}).get("group", {}).get("template-dev", {}).get("dependencies", {}) + + # Update regular dependencies in template pyproject.toml + for package, version in template_deps.items(): + # Skip packages that are conditionally included (those with cookiecutter variables) + if package in ["django-htmx", "django-ninja", "django-ninja-crud", "psycopg", "sentry-sdk", "whitenoise"]: + continue + + # For regular dependencies, update the version + if isinstance(version, dict) and "extras" in version: + # Handle dependencies with extras + version_str = f"{{extras = {version['extras']!r}, version = \"{version['version']}\"}}" + pattern = rf'{package}\s*=\s*{{[^}}]*}}' + template_content = re.sub(pattern, f"{package} = {version_str}", template_content) + else: + # Handle regular dependencies + version_str = str(version) + pattern = rf'{package}\s*=\s*"[^"]+"' + template_content = re.sub(pattern, f'{package} = "{version_str}"', template_content) + + # Update dev dependencies in template pyproject.toml + for package, version in template_dev_deps.items(): + pattern = rf'{package}\s*=\s*"[^"]+"' + template_content = re.sub(pattern, f'{package} = "{version}"', template_content) + + # Write back the updated template pyproject.toml + with open("{{cookiecutter.project_slug}}/pyproject.toml", 'w') as f: + f.write(template_content) + + +if __name__ == "__main__": + update_template_pyproject() + print("Template dependencies have been synchronized successfully!") \ No newline at end of file diff --git a/.github/workflows/sync-dependencies.yml b/.github/workflows/sync-dependencies.yml new file mode 100644 index 0000000..b63a89d --- /dev/null +++ b/.github/workflows/sync-dependencies.yml @@ -0,0 +1,49 @@ +name: Sync Dependencies + +on: + pull_request: + paths: + - 'pyproject.toml' + - '.github/workflows/sync-dependencies.yml' + +jobs: + sync-dependencies: + name: Sync Template Dependencies + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ github.head_ref }} + fetch-depth: 0 + + - name: Setup Python + uses: actions/setup-python@v5 + with: + python-version: '3.12' + + - name: Install Poetry + run: pip install poetry + + - name: Sync Dependencies + run: | + # Extract dependencies from root pyproject.toml template group + python .github/scripts/sync_dependencies.py + + - name: Run Poetry Lock in template directory + run: | + cd {{cookiecutter.project_slug}} + poetry lock + + - name: Commit and push changes if needed + run: | + git config --local user.email "action@github.com" + git config --local user.name "GitHub Action" + + if [[ $(git diff --name-only | grep -c "{{cookiecutter.project_slug}}/pyproject.toml\|{{cookiecutter.project_slug}}/poetry.lock") -gt 0 ]]; then + git add {{cookiecutter.project_slug}}/pyproject.toml {{cookiecutter.project_slug}}/poetry.lock + git commit -m "Sync template dependencies from root" -m "Automated by sync-dependencies workflow" + git push + else + echo "No changes to commit" + fi \ No newline at end of file diff --git a/README.md b/README.md index 3e234bc..b5d4f0a 100644 --- a/README.md +++ b/README.md @@ -132,5 +132,18 @@ To avoid these migration issues, the custom user model is created in an isolated +## Dependency Management + +The template manages dependencies in two locations: +- Root `pyproject.toml`: Contains dependencies for the template itself +- `{{cookiecutter.project_slug}}/pyproject.toml`: Contains dependencies for projects generated from the template + +To ensure consistent dependency updates, the template dependencies are synchronized through: +1. A "template" group in the root `pyproject.toml` that mirrors the dependencies in `{{cookiecutter.project_slug}}/pyproject.toml` +2. A GitHub workflow that automatically syncs dependencies from the root file to the template file on pull requests + +This allows Dependabot to update all dependencies by targeting the root `pyproject.toml`, and those updates are automatically propagated to the template. + + ## Contribute Contributions are welcome, feel free to suggest improvements. diff --git a/pyproject.toml b/pyproject.toml index 71ec631..d37a5e5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -20,6 +20,28 @@ pytest = "^8.3.5" pytest-cookies = "^0.7.0" pre-commit = "^4.2.0" +[tool.poetry.group.template.dependencies] +# Dependencies for the template project (automatically synced to {{cookiecutter.project_slug}}/pyproject.toml) +dj-database-url = "2.2.0" +django = "5.0.6" +django-extensions = "3.2.3" +django-htmx = "1.23.0" +django-ninja = "1.2.0" +django-ninja-crud = "0.2.0" +gunicorn = "23.0.0" +psycopg = "3.2.9" +python-decouple = "3.8" +sentry-sdk = {extras = ["django"], version = "2.7.1"} +whitenoise = {extras = ["brotli"], version = "6.7.0"} + +# Template dev dependencies +[tool.poetry.group.template-dev.dependencies] +model-bakery = "1.19.5" +pre-commit = "3.8.0" +pytest = "8.3.3" +pytest-django = "4.9.0" +pytest-mock = "3.14.0" + [tool.pytest.ini_options] testpaths = "tests/"