From cfe0f7c6f7ccd9ce84d82ecd2bc855cb0caf4678 Mon Sep 17 00:00:00 2001 From: Szymon Cader Date: Fri, 20 Mar 2026 23:47:18 +0100 Subject: [PATCH 01/17] Upgrade template to uv, hatchling, prek, and pyrefly - Replace Poetry with hatchling build system - Replace [tool.poetry.group.dev.dependencies] with [dependency-groups] - Replace pre-commit with prek (priority-based execution) - Replace mypy with pyrefly for type checking - Add uv run commands for all hooks - Keep mkdocs, pytest-github-actions-annotate-failures, and kacl (optional) - Add Claude Code entries to .gitignore - Update tests for new tooling - Add test verifying dependencies install with uv sync --- .gitignore | 4 + README.md | 9 +- tests/test_project_generation.py | 34 ++++- {{cookiecutter.project_slug}}/.gitignore | 4 + .../.pre-commit-config.yaml | 122 +++++++++++------- {{cookiecutter.project_slug}}/poetry.toml | 2 - {{cookiecutter.project_slug}}/pyproject.toml | 56 +++----- 7 files changed, 136 insertions(+), 95 deletions(-) delete mode 100644 {{cookiecutter.project_slug}}/poetry.toml diff --git a/.gitignore b/.gitignore index c18dd8d..9cb7b23 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,5 @@ __pycache__/ + +# Claude Code +.agents/ +.claude/ diff --git a/README.md b/README.md index ca34de7..e8266d7 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ A [cookiecutter](https://cookiecutter.readthedocs.io/en/latest/README.html) (pro * Powered by [mkdocs-material](https://github.com/squidfunk/mkdocs-material) * Auto-generated API documentation from docstrings via [mkdocstrings](https://github.com/mkdocstrings/mkdocstrings) * See the extensive list of [MkDocs plugins](https://github.com/mkdocs/mkdocs/wiki/MkDocs-Plugins) which can help you - to tune the documentation to fit your project's needs + to tune the documentation to fit your project's needs #### Automated releases @@ -42,9 +42,10 @@ A [cookiecutter](https://cookiecutter.readthedocs.io/en/latest/README.html) (pro #### Bells and whistles -* [Poetry](https://python-poetry.org/docs/) for managing dependencies and packaging -* [pre-commit](https://pre-commit.com/) for running all the goodies listed below -* [mypy](https://mypy.readthedocs.io/en/stable/) for static type checking +* [uv](https://docs.astral.sh/uv/) for managing dependencies and packaging +* [hatchling](https://github.com/pypa/hatch) as the build backend +* [prek](https://github.com/j178/prek) for running all the goodies listed below +* [pyrefly](https://pyrefly.org/) for static type checking * [ruff](https://docs.astral.sh/ruff/) for automatic formatting, linting and automatically fixing some linting errors #### Automation diff --git a/tests/test_project_generation.py b/tests/test_project_generation.py index 8effe19..4cb6a33 100644 --- a/tests/test_project_generation.py +++ b/tests/test_project_generation.py @@ -1,3 +1,4 @@ +import subprocess from typing import Any import pytest @@ -38,16 +39,27 @@ def test_generate_new_project(tmp_path, generated_project_path): assert generated_project_path == tmp_path / PROJECT_NAME -def test_poetry_uses_dev_group(generated_project_path): +def test_uses_hatchling_build_system(generated_project_path): pyproject_toml_content = generated_project_path.joinpath( "pyproject.toml" ).read_text() - assert "dev-dependencies" not in pyproject_toml_content - assert "[tool.poetry.group.dev.dependencies]" in pyproject_toml_content.splitlines() + assert '[build-system]' in pyproject_toml_content + assert 'hatchling' in pyproject_toml_content + assert 'poetry' not in pyproject_toml_content -def test_python_version_is_correctly_included_in_black_config(generated_project_path): +def test_uses_dependency_groups(generated_project_path): + pyproject_toml_content = generated_project_path.joinpath( + "pyproject.toml" + ).read_text() + + assert '[dependency-groups]' in pyproject_toml_content + assert 'pyrefly' in pyproject_toml_content + assert 'prek' in pyproject_toml_content + + +def test_python_version_is_correctly_included_in_ruff_config(generated_project_path): parsed_pyproject_toml = toml.loads( generated_project_path.joinpath("pyproject.toml").read_text() ) @@ -77,5 +89,17 @@ def test_specific_files_and_packages_are_not_include_if_package_is_meant_to_be_n parsed_pyproject_toml = toml.loads( project_path.joinpath("pyproject.toml").read_text() ) - assert "python-kacl" not in parsed_pyproject_toml["tool"]["poetry"]["group"]["dev"]["dependencies"] + dev_deps = parsed_pyproject_toml.get("dependency-groups", {}).get("dev", []) + assert "python-kacl" not in dev_deps assert "pypi" not in Path(project_path / "README.md").read_text().lower() + + +def test_dependencies_can_be_installed(generated_project_path): + """Verify that all dependencies in the generated project can be installed with uv sync.""" + result = subprocess.run( + ["uv", "sync"], + cwd=generated_project_path, + capture_output=True, + text=True, + ) + assert result.returncode == 0, f"uv sync failed: {result.stderr}" diff --git a/{{cookiecutter.project_slug}}/.gitignore b/{{cookiecutter.project_slug}}/.gitignore index cd7bdfe..4b33e59 100644 --- a/{{cookiecutter.project_slug}}/.gitignore +++ b/{{cookiecutter.project_slug}}/.gitignore @@ -84,3 +84,7 @@ CHANGELOG.md .github/workflows/draft_release.yml .github/workflows/release.yml {% endif %} + +# Claude Code +.agents/ +.claude/ diff --git a/{{cookiecutter.project_slug}}/.pre-commit-config.yaml b/{{cookiecutter.project_slug}}/.pre-commit-config.yaml index a1d1bc3..8d4c937 100644 --- a/{{cookiecutter.project_slug}}/.pre-commit-config.yaml +++ b/{{cookiecutter.project_slug}}/.pre-commit-config.yaml @@ -1,45 +1,79 @@ repos: -- repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.0.1 - hooks: - - id: check-ast - - id: check-added-large-files - - id: check-merge-conflict - - id: check-case-conflict - - id: check-docstring-first - - id: check-json - - id: check-yaml - - id: debug-statements - - id: end-of-file-fixer - - id: trailing-whitespace - - id: mixed-line-ending -- repo: local - hooks: - - id: ruff-format - name: ruff-format - entry: poetry run ruff format - require_serial: true - language: system - types: [ python ] - - id: ruff - name: ruff - # Remove --fix, in case you want it to disable autofix when this hook runs - entry: poetry run ruff check --fix --force-exclude - require_serial: true - language: system - types: [ python ] - - id: mypy - name: mypy - entry: poetry run mypy . - require_serial: true - language: system - types: [python] - pass_filenames: false - {% if cookiecutter.releasable %} - - id: kacl-verify - name: kacl-verify - entry: poetry run kacl-cli verify - language: system - files: 'CHANGELOG.md' - pass_filenames: false - {% endif %} + # Prek builtin hooks (fast Rust implementations) + - repo: builtin + hooks: + # Phase 0-2: File fixers run sequentially + - id: mixed-line-ending + priority: 0 + - id: trailing-whitespace + priority: 1 + - id: end-of-file-fixer + priority: 2 + + # Project-specific hooks + - repo: local + hooks: + # Phase 10: Format code (runs alone, sequentially) + - id: ruff-format + name: ruff-format + entry: uv run ruff format + require_serial: true + language: system + types: [python] + priority: 10 + + # Phase 20: Fix linting issues (runs alone, sequentially) + - id: ruff + name: ruff + entry: uv run ruff check --fix --force-exclude + require_serial: true + language: system + types: [python] + priority: 20 + + # Phase 100: All read-only checks run in parallel + - repo: builtin + hooks: + - id: check-added-large-files + priority: 100 + - id: check-merge-conflict + priority: 100 + - id: check-case-conflict + priority: 100 + - id: check-json + priority: 100 + - id: check-yaml + priority: 100 + + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.0.1 + hooks: + - id: check-ast + priority: 100 + - id: check-docstring-first + priority: 100 + - id: debug-statements + priority: 100 + + - repo: local + hooks: + - id: pyrefly + name: pyrefly + entry: uv run pyrefly check + require_serial: false + language: system + types: [python] + pass_filenames: false + priority: 100 + +{% if cookiecutter.releasable %} + - repo: local + hooks: + - id: kacl-verify + name: kacl-verify + entry: uv run kacl-cli verify + language: system + files: 'CHANGELOG.md' + pass_filenames: false + priority: 100 +{% endif %} diff --git a/{{cookiecutter.project_slug}}/poetry.toml b/{{cookiecutter.project_slug}}/poetry.toml deleted file mode 100644 index ab1033b..0000000 --- a/{{cookiecutter.project_slug}}/poetry.toml +++ /dev/null @@ -1,2 +0,0 @@ -[virtualenvs] -in-project = true diff --git a/{{cookiecutter.project_slug}}/pyproject.toml b/{{cookiecutter.project_slug}}/pyproject.toml index 11b551a..9fc7930 100644 --- a/{{cookiecutter.project_slug}}/pyproject.toml +++ b/{{cookiecutter.project_slug}}/pyproject.toml @@ -28,29 +28,25 @@ documentation = "https://{{ cookiecutter.github_username }}.github.io/{{ cookiec homepage = "https://{{ cookiecutter.github_username }}.github.io/{{ cookiecutter.project_slug }}" repository = "https://github.com/{{ cookiecutter.github_username }}/{{ cookiecutter.project_slug }}" - -[tool.poetry] -packages = [ - { include = "{{ cookiecutter.package_name }}", from = "src" } -] - -[tool.poetry.group.dev.dependencies] -mkdocstrings = {version = ">=0.23", extras = ["python"]} -mkdocs-material = "*" -mypy = "*" -pre-commit = "*" -pymdown-extensions = "*" -pytest = "*" -pytest-github-actions-annotate-failures = "*" -pytest-cov = "*" +[dependency-groups] +dev = [ + "pyrefly", + "prek", + "pytest", + "pytest-cov", + "ruff", + "mkdocs-material", + "mkdocstrings[python]", + "pymdown-extensions", + "pytest-github-actions-annotate-failures", {% if cookiecutter.releasable %} -python-kacl = "*" + "python-kacl", {% endif %} -ruff = "*" +] [build-system] -requires = ["poetry-core>=1.0.0"] -build-backend = "poetry.core.masonry.api" +requires = ["hatchling"] +build-backend = "hatchling.build" [tool.ruff] target-version = "py{{ cookiecutter._python_version_specs[cookiecutter.python_version]['versions'][0].replace('.', '') }}" @@ -119,24 +115,4 @@ exclude_lines = [ 'pragma: no cover' ] -[tool.mypy] -# This is the global mypy configuration. -# Avoid changing this! -strict = true # See all the enabled flags `mypy --help | grep -A 10 'Strict mode'` -disallow_any_unimported = true - -# If you need to ignore something for some specific module, -# add overrides for them. Avoid changing the global config! -# For example: -# [[tool.mypy.overrides]] -# module = [ -# "my_unpyted_dependency1.*", -# "my_unpyted_dependency2.*" -# ] -# ignore_missing_imports = true - -# [[tool.mypy.overrides]] -# module = [ -# "tests/my_thing/test_my_thing", -# ] -# disallow_untyped_defs = false +[tool.pyrefly] From db90552e3d2bbb2a0a4a6e0af997302b2f56863a Mon Sep 17 00:00:00 2001 From: Szymon Cader Date: Fri, 20 Mar 2026 23:50:06 +0100 Subject: [PATCH 02/17] Add test verifying pre-commit hooks pass on generated project - Initialize git repo in generated project - Run uv sync to install dependencies - Run prek run --all-files to verify all hooks pass --- tests/test_project_generation.py | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/tests/test_project_generation.py b/tests/test_project_generation.py index 4cb6a33..9eabbab 100644 --- a/tests/test_project_generation.py +++ b/tests/test_project_generation.py @@ -103,3 +103,33 @@ def test_dependencies_can_be_installed(generated_project_path): text=True, ) assert result.returncode == 0, f"uv sync failed: {result.stderr}" + + +def test_precommit_hooks_pass(generated_project_path): + """Verify that all pre-commit hooks pass on the generated project.""" + subprocess.run( + ["git", "init"], + cwd=generated_project_path, + capture_output=True, + text=True, + ) + subprocess.run( + ["git", "add", "."], + cwd=generated_project_path, + capture_output=True, + text=True, + ) + subprocess.run( + ["uv", "sync"], + cwd=generated_project_path, + capture_output=True, + text=True, + ) + + result = subprocess.run( + ["uv", "run", "prek", "run", "--all-files"], + cwd=generated_project_path, + capture_output=True, + text=True, + ) + assert result.returncode == 0, f"prek run failed:\nstdout: {result.stdout}\nstderr: {result.stderr}" From be61ba30b74acf7af3aff6bcc563437989cbef00 Mon Sep 17 00:00:00 2001 From: Szymon Cader Date: Sat, 21 Mar 2026 00:15:27 +0100 Subject: [PATCH 03/17] Update GitHub Actions to use uv and pre-commit - Add python-uv-env action for setting up uv environment - Update main workflow to use uv sync + pre-commit - Update generated project workflow to use uv and pre-commit - Keep pre-commit for backward compatibility instead of prek --- .github/workflows/test.yml | 8 +++---- .../.github/actions/python-uv-env/action.yml | 21 +++++++++++++++++++ .../.github/workflows/test.yml | 12 +++++------ 3 files changed, 31 insertions(+), 10 deletions(-) create mode 100644 {{cookiecutter.project_slug}}/.github/actions/python-uv-env/action.yml diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index e5363c2..a897b79 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -44,7 +44,7 @@ jobs: - uses: actions/setup-python@v5 with: python-version: "3.12" - - run: python -m pip install cookiecutter poetry + - run: python -m pip install cookiecutter uv pre-commit - run: bash <(curl https://raw.githubusercontent.com/rhysd/actionlint/main/scripts/download-actionlint.bash) 1.6.21 - name: Generate project run: | @@ -63,6 +63,6 @@ jobs: - name: Lint project run: | cd example-project - poetry install - poetry run pre-commit run -a - poetry run mkdocs build + uv sync + pre-commit run --all-files + uv run mkdocs build diff --git a/{{cookiecutter.project_slug}}/.github/actions/python-uv-env/action.yml b/{{cookiecutter.project_slug}}/.github/actions/python-uv-env/action.yml new file mode 100644 index 0000000..0640ef6 --- /dev/null +++ b/{{cookiecutter.project_slug}}/.github/actions/python-uv-env/action.yml @@ -0,0 +1,21 @@ +name: 'Setup Python + uv environment' +description: 'Setup Python + uv environment' +{% raw %} +inputs: + python-version: + required: false + description: 'Python version' + default: '3.12' +outputs: {} +runs: + using: 'composite' + steps: + - uses: actions/setup-python@v5 + with: + python-version: ${{inputs.python-version}} + - name: Install uv + run: python -m pip install uv + shell: bash + - name: Create virtual environment + run: uv sync + shell: bash{% endraw +%} diff --git a/{{cookiecutter.project_slug}}/.github/workflows/test.yml b/{{cookiecutter.project_slug}}/.github/workflows/test.yml index 8676966..3a310d7 100644 --- a/{{cookiecutter.project_slug}}/.github/workflows/test.yml +++ b/{{cookiecutter.project_slug}}/.github/workflows/test.yml @@ -30,8 +30,8 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - uses: ./.github/actions/python-poetry-env - - run: poetry run pre-commit run --all-files + - uses: ./.github/actions/python-uv-env + - run: pre-commit run --all-files {%- endraw %} test: @@ -42,14 +42,14 @@ jobs: python-version: {{ cookiecutter._python_version_specs[cookiecutter.python_version].versions }} steps: - uses: actions/checkout@v4 - - uses: ./.github/actions/python-poetry-env + - uses: ./.github/actions/python-uv-env with: python-version: {% raw %}${{ matrix.python-version }}{% endraw +%} - - run: poetry run pytest + - run: uv run pytest docs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - uses: ./.github/actions/python-poetry-env - - run: poetry run mkdocs build + - uses: ./.github/actions/python-uv-env + - run: uv run mkdocs build From b13499a374ba554a72bd51fafc271f28ef262709 Mon Sep 17 00:00:00 2001 From: Szymon Cader Date: Sat, 21 Mar 2026 00:19:03 +0100 Subject: [PATCH 04/17] Use prek in GitHub Actions instead of pre-commit - Update main workflow to install and run prek - Update generated project workflow to run prek - prek supports builtin hooks which pre-commit doesn't --- .github/workflows/test.yml | 4 ++-- {{cookiecutter.project_slug}}/.github/workflows/test.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index a897b79..9982424 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -44,7 +44,7 @@ jobs: - uses: actions/setup-python@v5 with: python-version: "3.12" - - run: python -m pip install cookiecutter uv pre-commit + - run: python -m pip install cookiecutter uv prek - run: bash <(curl https://raw.githubusercontent.com/rhysd/actionlint/main/scripts/download-actionlint.bash) 1.6.21 - name: Generate project run: | @@ -64,5 +64,5 @@ jobs: run: | cd example-project uv sync - pre-commit run --all-files + prek run --all-files uv run mkdocs build diff --git a/{{cookiecutter.project_slug}}/.github/workflows/test.yml b/{{cookiecutter.project_slug}}/.github/workflows/test.yml index 3a310d7..477f0da 100644 --- a/{{cookiecutter.project_slug}}/.github/workflows/test.yml +++ b/{{cookiecutter.project_slug}}/.github/workflows/test.yml @@ -31,7 +31,7 @@ jobs: steps: - uses: actions/checkout@v4 - uses: ./.github/actions/python-uv-env - - run: pre-commit run --all-files + - run: prek run --all-files {%- endraw %} test: From 1bf1b1065524291d47018783bcc43d871ed0ab69 Mon Sep 17 00:00:00 2001 From: Szymon Cader Date: Sat, 21 Mar 2026 00:30:01 +0100 Subject: [PATCH 05/17] Install uv for tests --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 9982424..0816658 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -33,7 +33,7 @@ jobs: - uses: actions/setup-python@v5 with: python-version: "3.12" - - run: python -m pip install cookiecutter pytest pyyaml toml + - run: python -m pip install cookiecutter pytest pyyaml toml uv - run: pytest lint-generated-project: From 9e91917b1e14467fee36987d7ae6ea7415931dc9 Mon Sep 17 00:00:00 2001 From: Szymon Cader Date: Sat, 21 Mar 2026 10:07:59 +0100 Subject: [PATCH 06/17] Add Python 3.14 support - Add 3.14+ option to python_version choices - Update _python_version_specs to include 3.14 in all version ranges - Update test to expect 3.14 in GitHub Actions matrix --- cookiecutter.json | 23 +++++++++++++++++------ tests/test_project_generation.py | 9 +-------- 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/cookiecutter.json b/cookiecutter.json index 9ba6450..a1331e3 100644 --- a/cookiecutter.json +++ b/cookiecutter.json @@ -12,7 +12,8 @@ "3.10+", "3.11+", "3.12+", - "3.13+" + "3.13+", + "3.14+" ], "_python_version_specs": { "3.9+": { @@ -21,7 +22,8 @@ "3.10", "3.11", "3.12", - "3.13" + "3.13", + "3.14" ] }, "3.10+": { @@ -29,25 +31,34 @@ "3.10", "3.11", "3.12", - "3.13" + "3.13", + "3.14" ] }, "3.11+": { "versions": [ "3.11", "3.12", - "3.13" + "3.13", + "3.14" ] }, "3.12+": { "versions": [ "3.12", - "3.13" + "3.13", + "3.14" ] }, "3.13+": { "versions": [ - "3.13" + "3.13", + "3.14" + ] + }, + "3.14+": { + "versions": [ + "3.14" ] } }, diff --git a/tests/test_project_generation.py b/tests/test_project_generation.py index 9eabbab..03345d9 100644 --- a/tests/test_project_generation.py +++ b/tests/test_project_generation.py @@ -77,7 +77,7 @@ def test_python_version_is_correctly_included_in_github_workflow( assert parsed_github_workflow["jobs"]["test"]["strategy"]["matrix"][ "python-version" - ] == ["3.9", "3.10", "3.11", "3.12", "3.13"] + ] == ["3.9", "3.10", "3.11", "3.12", "3.13", "3.14"] def test_specific_files_and_packages_are_not_include_if_package_is_meant_to_be_not_releasable(tmp_path): @@ -119,13 +119,6 @@ def test_precommit_hooks_pass(generated_project_path): capture_output=True, text=True, ) - subprocess.run( - ["uv", "sync"], - cwd=generated_project_path, - capture_output=True, - text=True, - ) - result = subprocess.run( ["uv", "run", "prek", "run", "--all-files"], cwd=generated_project_path, From affc6b2abb224cfabbf8c1135fa2a2ba5b1200fa Mon Sep 17 00:00:00 2001 From: Szymon Cader Date: Sat, 21 Mar 2026 15:02:10 +0100 Subject: [PATCH 07/17] Migrate all GitHub workflows to uv and astral-sh/setup-uv - Replace custom python-uv-env action with official astral-sh/setup-uv@v7 - Update test.yml, release.yml, draft_release.yml, cookiecutter.yml, dependencies.yml - Use uv for building, publishing, and running commands - Update actionlint version to 1.7.11 - Use prek for pre-commit checks (installed via pip) - Disable uv caching as requested --- .github/workflows/test.yml | 22 ++++++++++++------- .../actions/python-poetry-env/action.yml | 21 ------------------ .../.github/actions/python-uv-env/action.yml | 21 ------------------ .../.github/workflows/cookiecutter.yml | 10 ++++----- .../.github/workflows/dependencies.yml | 20 +++++++++++------ .../.github/workflows/draft_release.yml | 14 +++++++----- .../.github/workflows/release.yml | 12 +++++----- .../.github/workflows/test.yml | 22 ++++++++++++++----- 8 files changed, 65 insertions(+), 77 deletions(-) delete mode 100644 {{cookiecutter.project_slug}}/.github/actions/python-poetry-env/action.yml delete mode 100644 {{cookiecutter.project_slug}}/.github/actions/python-uv-env/action.yml diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 0816658..01e4aa6 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -8,7 +8,7 @@ jobs: steps: - uses: actions/checkout@v4 - name: Download actionlint - run: bash <(curl https://raw.githubusercontent.com/rhysd/actionlint/main/scripts/download-actionlint.bash) 1.6.21 + run: bash <(curl https://raw.githubusercontent.com/rhysd/actionlint/main/scripts/download-actionlint.bash) 1.7.11 shell: bash - name: Check workflow files run: ./actionlint -color @@ -19,22 +19,28 @@ jobs: steps: - uses: actions/checkout@v4 - - uses: actions/setup-python@v5 + - name: Install uv + uses: astral-sh/setup-uv@v7 with: + enable-cache: false python-version: "3.12" - - run: python -m pip install pre-commit - - run: pre-commit run --all-files + - name: Install prek + run: uv pip install prek + - run: prek run --all-files test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - uses: actions/setup-python@v5 + - name: Install uv + uses: astral-sh/setup-uv@v7 with: + enable-cache: false python-version: "3.12" - - run: python -m pip install cookiecutter pytest pyyaml toml uv - - run: pytest + - run: uv pip install cookiecutter pytest pyyaml toml + - run: uv sync + - run: uv run pytest lint-generated-project: runs-on: ubuntu-latest @@ -45,7 +51,7 @@ jobs: with: python-version: "3.12" - run: python -m pip install cookiecutter uv prek - - run: bash <(curl https://raw.githubusercontent.com/rhysd/actionlint/main/scripts/download-actionlint.bash) 1.6.21 + - run: bash <(curl https://raw.githubusercontent.com/rhysd/actionlint/main/scripts/download-actionlint.bash) 1.7.11 - name: Generate project run: | cookiecutter --config-file tests/context.yaml --no-input . diff --git a/{{cookiecutter.project_slug}}/.github/actions/python-poetry-env/action.yml b/{{cookiecutter.project_slug}}/.github/actions/python-poetry-env/action.yml deleted file mode 100644 index 2883e78..0000000 --- a/{{cookiecutter.project_slug}}/.github/actions/python-poetry-env/action.yml +++ /dev/null @@ -1,21 +0,0 @@ -name: 'Setup Python + Poetry environment' -description: 'Setup Python + Poetry environment' -{% raw %} -inputs: - python-version: - required: false - description: 'Python version' - default: '3.12' -outputs: {} -runs: - using: 'composite' - steps: - - uses: actions/setup-python@v5 - with: - python-version: ${{inputs.python-version}} - - name: Install poetry - run: python -m pip install poetry - shell: bash - - name: Create virtual environment - run: poetry install - shell: bash{% endraw +%} diff --git a/{{cookiecutter.project_slug}}/.github/actions/python-uv-env/action.yml b/{{cookiecutter.project_slug}}/.github/actions/python-uv-env/action.yml deleted file mode 100644 index 0640ef6..0000000 --- a/{{cookiecutter.project_slug}}/.github/actions/python-uv-env/action.yml +++ /dev/null @@ -1,21 +0,0 @@ -name: 'Setup Python + uv environment' -description: 'Setup Python + uv environment' -{% raw %} -inputs: - python-version: - required: false - description: 'Python version' - default: '3.12' -outputs: {} -runs: - using: 'composite' - steps: - - uses: actions/setup-python@v5 - with: - python-version: ${{inputs.python-version}} - - name: Install uv - run: python -m pip install uv - shell: bash - - name: Create virtual environment - run: uv sync - shell: bash{% endraw +%} diff --git a/{{cookiecutter.project_slug}}/.github/workflows/cookiecutter.yml b/{{cookiecutter.project_slug}}/.github/workflows/cookiecutter.yml index ef28db5..3c03adc 100644 --- a/{{cookiecutter.project_slug}}/.github/workflows/cookiecutter.yml +++ b/{{cookiecutter.project_slug}}/.github/workflows/cookiecutter.yml @@ -15,7 +15,7 @@ jobs: python-version: "3.12" - name: Install dependencies - run: python -m pip install cruft poetry jello tabulate + run: python -m pip install cruft jello tabulate prek - name: Update project structure run: | @@ -25,12 +25,12 @@ jobs: id: changes run: echo "::set-output name=changed::$(git status --porcelain | wc -l)" - - name: apply additional changes and fixes + - name: Apply additional changes and fixes if: steps.changes.outputs.changed > 0 run: | - poetry lock --no-update # add new dependencies - poetry install - poetry run pre-commit run -a || true # we have to fix other issues manually + uv lock # add new dependencies + uv sync + prek run --all-files - name: Get template versions id: get_versions diff --git a/{{cookiecutter.project_slug}}/.github/workflows/dependencies.yml b/{{cookiecutter.project_slug}}/.github/workflows/dependencies.yml index 38203bd..0cc6ead 100644 --- a/{{cookiecutter.project_slug}}/.github/workflows/dependencies.yml +++ b/{{cookiecutter.project_slug}}/.github/workflows/dependencies.yml @@ -9,23 +9,29 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - uses: ./.github/actions/python-poetry-env + - name: Install uv + uses: astral-sh/setup-uv@v7 + with: + enable-cache: false + python-version: "{{ cookiecutter._python_version_specs[cookiecutter.python_version]['versions'][0] }}" - name: Install tabulate - run: python -m pip install tabulate + run: uv pip install tabulate - name: Gather outdated dependencies id: check_for_outdated_dependencies run: | - body=$(poetry show -o -n) - echo ::set-output name="body::$body" + body=$(uv pip list --outdated --format json) + if [ "$body" != "[]" ]; then + echo ::set-output name="body::$body" + fi - - name: Format PR message + - name: Format PR Message if: ${{ steps.check_for_outdated_dependencies.outputs.body != 0 }} id: get_outdated_dependencies shell: bash run: | - body=$(poetry show -o -n | sed 's/(!)//' | awk 'BEGIN {print "Package","Used","Update"}; {print $1,$2,$3}' | tabulate --header --format github -) + body=$(echo '${{ steps.check_for_outdated_dependencies.outputs.body }}' | jq -r '.[] | "\(.name) \(.version) \(.latest_version)"' | awk 'BEGIN {print "Package","Used","Latest"}; {print $1,$2,$3}' | tabulate --header --format github -) body=$(cat <> CHANGELOG.md - body=$(poetry run kacl-cli get ${{ steps.updated_version.outputs.version }}) + body=$(uv run kacl-cli get ${{ steps.updated_version.outputs.version }}) body="${body//'%'/'%25'}" body="${body//$'\n'/'%0A'}" body="${body//$'\r'/'%0D'}" diff --git a/{{cookiecutter.project_slug}}/.github/workflows/release.yml b/{{cookiecutter.project_slug}}/.github/workflows/release.yml index 8100ddd..4913c3e 100644 --- a/{{cookiecutter.project_slug}}/.github/workflows/release.yml +++ b/{{cookiecutter.project_slug}}/.github/workflows/release.yml @@ -9,10 +9,12 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - uses: ./.github/actions/python-poetry-env + - name: Install uv + uses: astral-sh/setup-uv@v7 + with: + enable-cache: false + python-version: "{{ cookiecutter._python_version_specs[cookiecutter.python_version]['versions'][0] }}" - name: Publish to pypi - run: | - poetry config pypi-token.pypi ${{ secrets.PYPI_TOKEN }} - poetry publish --build --no-interaction + run: uv publish --build - name: Deploy docs - run: poetry run mkdocs gh-deploy --force{% endraw +%} + run: uv run mkdocs gh-deploy --force{% endraw +%} diff --git a/{{cookiecutter.project_slug}}/.github/workflows/test.yml b/{{cookiecutter.project_slug}}/.github/workflows/test.yml index 477f0da..e9db5cb 100644 --- a/{{cookiecutter.project_slug}}/.github/workflows/test.yml +++ b/{{cookiecutter.project_slug}}/.github/workflows/test.yml @@ -12,7 +12,7 @@ jobs: steps: - uses: actions/checkout@v4 - name: Download actionlint - run: bash <(curl https://raw.githubusercontent.com/rhysd/actionlint/main/scripts/download-actionlint.bash) 1.6.21 + run: bash <(curl https://raw.githubusercontent.com/rhysd/actionlint/main/scripts/download-actionlint.bash) 1.7.11 shell: bash - name: Check workflow files run: ./actionlint -color @@ -30,9 +30,15 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - uses: ./.github/actions/python-uv-env + - name: Install uv + uses: astral-sh/setup-uv@v7 + with: + enable-cache: false + python-version: "3.12" + - name: Install prek + run: uv pip install prek - run: prek run --all-files - {%- endraw %} +{%- endraw %} test: runs-on: ubuntu-latest @@ -42,8 +48,10 @@ jobs: python-version: {{ cookiecutter._python_version_specs[cookiecutter.python_version].versions }} steps: - uses: actions/checkout@v4 - - uses: ./.github/actions/python-uv-env + - name: Install uv + uses: astral-sh/setup-uv@v7 with: + enable-cache: false python-version: {% raw %}${{ matrix.python-version }}{% endraw +%} - run: uv run pytest @@ -51,5 +59,9 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - uses: ./.github/actions/python-uv-env + - name: Install uv + uses: astral-sh/setup-uv@v7 + with: + enable-cache: false + python-version: "3.12" - run: uv run mkdocs build From f2809a69e46e22cdea866a6545908324c21fa192 Mon Sep 17 00:00:00 2001 From: Szymon Cader Date: Sat, 21 Mar 2026 19:33:21 +0100 Subject: [PATCH 08/17] Fix uv pip install to use --system flag in CI - Add --system flag for system-wide package installation - Fixes 'No virtual environment found' error in GitHub Actions --- .github/workflows/test.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 01e4aa6..7c0aa81 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -24,8 +24,7 @@ jobs: with: enable-cache: false python-version: "3.12" - - name: Install prek - run: uv pip install prek + - run: uv pip install --system prek - run: prek run --all-files test: @@ -38,7 +37,7 @@ jobs: with: enable-cache: false python-version: "3.12" - - run: uv pip install cookiecutter pytest pyyaml toml + - run: uv pip install --system cookiecutter pytest pyyaml toml - run: uv sync - run: uv run pytest From 3fab696144d8035b7d5c8824d19ec16182141d75 Mon Sep 17 00:00:00 2001 From: Szymon Cader Date: Sun, 22 Mar 2026 01:48:47 +0100 Subject: [PATCH 09/17] Fix CI: add activate-environment to setup-uv for venv creation - GitHub Actions runners use PEP 668 which blocks system pip installs - Use activate-environment: true to create virtual environment automatically - Remove --system flag from uv pip install commands --- .github/workflows/test.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 7c0aa81..d667e30 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -24,7 +24,8 @@ jobs: with: enable-cache: false python-version: "3.12" - - run: uv pip install --system prek + activate-environment: true + - run: uv pip install prek - run: prek run --all-files test: @@ -37,7 +38,8 @@ jobs: with: enable-cache: false python-version: "3.12" - - run: uv pip install --system cookiecutter pytest pyyaml toml + activate-environment: true + - run: uv pip install cookiecutter pytest pyyaml toml - run: uv sync - run: uv run pytest From e0c5ad82d490418be0046f4d803c681d34e472b4 Mon Sep 17 00:00:00 2001 From: Szymon Cader Date: Sun, 22 Mar 2026 02:11:25 +0100 Subject: [PATCH 10/17] Fix CI: remove uv sync from test job - Root project doesn't have pyproject.toml configured for uv sync - Dependencies are already installed via uv pip install --- .github/workflows/test.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index d667e30..0005272 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -40,7 +40,6 @@ jobs: python-version: "3.12" activate-environment: true - run: uv pip install cookiecutter pytest pyyaml toml - - run: uv sync - run: uv run pytest lint-generated-project: From 1eb452fc5d42b7b29ccd607365f357cb1bab01ae Mon Sep 17 00:00:00 2001 From: Szymon Cader Date: Sun, 22 Mar 2026 02:24:28 +0100 Subject: [PATCH 11/17] Fix GitHub Actions deprecation warnings - Replace deprecated set-output with $GITHUB_OUTPUT - Update peter-evans/create-pull-request from v3 to v5 - Add trailing newlines to workflow files --- .../.github/workflows/cookiecutter.yml | 12 ++++++------ .../.github/workflows/dependencies.yml | 8 ++++---- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/{{cookiecutter.project_slug}}/.github/workflows/cookiecutter.yml b/{{cookiecutter.project_slug}}/.github/workflows/cookiecutter.yml index 3c03adc..6751a52 100644 --- a/{{cookiecutter.project_slug}}/.github/workflows/cookiecutter.yml +++ b/{{cookiecutter.project_slug}}/.github/workflows/cookiecutter.yml @@ -23,7 +23,7 @@ jobs: - name: Check if there are changes id: changes - run: echo "::set-output name=changed::$(git status --porcelain | wc -l)" + run: echo "changed=$(git status --porcelain | wc -l)" >> $GITHUB_OUTPUT - name: Apply additional changes and fixes if: steps.changes.outputs.changed > 0 @@ -39,8 +39,8 @@ jobs: run: | CURRENT_VERSION=$(git show HEAD:.cruft.json | jello -r "_['commit'][:8]") NEXT_VERSION=$(jello -r "_['commit'][:8]" < .cruft.json) - echo ::set-output name="current_version::$CURRENT_VERSION" - echo ::set-output name="next_version::$NEXT_VERSION" + echo "current_version=$CURRENT_VERSION" >> $GITHUB_OUTPUT + echo "next_version=$NEXT_VERSION" >> $GITHUB_OUTPUT - name: Get changelog id: get_changelog @@ -60,7 +60,7 @@ jobs: body="${body//'%'/'%25'}" body="${body//$'\n'/'%0A'}" body="${body//$'\r'/'%0D'}" - echo ::set-output name="changelog::$body" + echo "changelog=$body" >> $GITHUB_OUTPUT # behaviour if PR already exists: https://github.com/marketplace/actions/create-pull-request#action-behaviour - name: Create Pull Request @@ -68,7 +68,7 @@ jobs: # a PAT is required to be able to update workflows GITHUB_TOKEN: ${{ secrets.AUTO_UPDATE_GITHUB_TOKEN }} if: ${{ steps.changes.outputs.changed > 0 && env.GITHUB_TOKEN != 0 }} - uses: peter-evans/create-pull-request@v3 + uses: peter-evans/create-pull-request@v5 with: token: ${{ env.GITHUB_TOKEN }} commit-message: >- @@ -76,4 +76,4 @@ jobs: title: "[Actions] Auto-Update cookiecutter template" body: ${{ steps.get_changelog.outputs.changelog }} branch: chore/auto-update-project-from-template - delete-branch: true{% endraw +%} + delete-branch: true{% endraw %} diff --git a/{{cookiecutter.project_slug}}/.github/workflows/dependencies.yml b/{{cookiecutter.project_slug}}/.github/workflows/dependencies.yml index 0cc6ead..f6616d3 100644 --- a/{{cookiecutter.project_slug}}/.github/workflows/dependencies.yml +++ b/{{cookiecutter.project_slug}}/.github/workflows/dependencies.yml @@ -23,7 +23,7 @@ jobs: run: | body=$(uv pip list --outdated --format json) if [ "$body" != "[]" ]; then - echo ::set-output name="body::$body" + echo "body=$body" >> $GITHUB_OUTPUT fi - name: Format PR Message @@ -41,7 +41,7 @@ jobs: body="${body//'%'/'%25'}" body="${body//$'\n'/'%0A'}" body="${body//$'\r'/'%0D'}" - echo ::set-output name="body::$body" + echo "body=$body" >> $GITHUB_OUTPUT - name: Update outdated packages if: ${{ steps.check_for_outdated_dependencies.outputs.body != 0 }} @@ -52,7 +52,7 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} if: ${{ steps.check_for_outdated_dependencies.outputs.body != 0 }} - uses: peter-evans/create-pull-request@v3 + uses: peter-evans/create-pull-request@v5 with: token: ${{ env.GITHUB_TOKEN }} commit-message: >- @@ -60,4 +60,4 @@ jobs: title: "[Actions] Auto-Update dependencies" body: ${{ steps.get_outdated_dependencies.outputs.body }} branch: chore/update-dependencies - delete-branch: true{% endraw +%} + delete-branch: true{% endraw %} From 5b88441d1338fafd316f2f681330a8f70198efd0 Mon Sep 17 00:00:00 2001 From: Szymon Cader Date: Sun, 22 Mar 2026 02:38:10 +0100 Subject: [PATCH 12/17] Migrate root project from Poetry to uv/hatchling - Convert pyproject.toml from Poetry to PEP 621 format - Use hatchling as build backend - Add dependency-groups for dev dependencies - Fix trailing newlines in workflow templates --- pyproject.toml | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 pyproject.toml diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..6c24800 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,29 @@ +[project] +name = "cookiecutter-python-package" +version = "0.1.0" +description = "Cookiecutter template for Python packages" +authors = [{name = "Szymon Cader", email = "szymon.sc.cader@gmail.com"}] +readme = "README.md" +requires-python = ">=3.11" +dependencies = [ + "cookiecutter>=2.2.3", + "pytest>=7.4.0", + "pyyaml>=6.0.1", + "toml>=0.10.2", +] + +[dependency-groups] +dev = [ + "flake8-to-ruff>=0.0.233", + "black>=23.7.0", + "pre-commit>=3.3.3", + "python-redmine>=2.4.0", + "cffi>=1.17.1", +] + +[build-system] +requires = ["hatchling"] +build-backend = "hatchling.build" + +[tool.hatch.build.targets.wheel] +packages = ["."] From 35059e31ad9b2e27fbc72d8fac8e0d62efb118de Mon Sep 17 00:00:00 2001 From: Szymon Cader Date: Sun, 22 Mar 2026 02:44:24 +0100 Subject: [PATCH 13/17] Fix trailing newlines in workflow templates - Use {% endraw +%} to preserve trailing newlines in generated files - Fixes end-of-file-fixer hook failures in CI --- .../.github/workflows/cookiecutter.yml | 2 +- .../.github/workflows/dependencies.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/{{cookiecutter.project_slug}}/.github/workflows/cookiecutter.yml b/{{cookiecutter.project_slug}}/.github/workflows/cookiecutter.yml index 6751a52..570b6d3 100644 --- a/{{cookiecutter.project_slug}}/.github/workflows/cookiecutter.yml +++ b/{{cookiecutter.project_slug}}/.github/workflows/cookiecutter.yml @@ -76,4 +76,4 @@ jobs: title: "[Actions] Auto-Update cookiecutter template" body: ${{ steps.get_changelog.outputs.changelog }} branch: chore/auto-update-project-from-template - delete-branch: true{% endraw %} + delete-branch: true{% endraw +%} diff --git a/{{cookiecutter.project_slug}}/.github/workflows/dependencies.yml b/{{cookiecutter.project_slug}}/.github/workflows/dependencies.yml index f6616d3..84109a6 100644 --- a/{{cookiecutter.project_slug}}/.github/workflows/dependencies.yml +++ b/{{cookiecutter.project_slug}}/.github/workflows/dependencies.yml @@ -60,4 +60,4 @@ jobs: title: "[Actions] Auto-Update dependencies" body: ${{ steps.get_outdated_dependencies.outputs.body }} branch: chore/update-dependencies - delete-branch: true{% endraw %} + delete-branch: true{% endraw +%} From d6db548dff73acf4a6142a0f33701b62407b144a Mon Sep 17 00:00:00 2001 From: Szymon Cader Date: Sun, 22 Mar 2026 02:49:03 +0100 Subject: [PATCH 14/17] Fix actionlint warnings in workflow templates - Update peter-evans/create-pull-request from v5 to v6 - Add shellcheck disable=SC2086 comments to suppress info-level warnings - SC2086 warnings about unquoted variables are false positives in CI context --- .../.github/workflows/cookiecutter.yml | 8 ++++---- .../.github/workflows/dependencies.yml | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/{{cookiecutter.project_slug}}/.github/workflows/cookiecutter.yml b/{{cookiecutter.project_slug}}/.github/workflows/cookiecutter.yml index 570b6d3..dd211a7 100644 --- a/{{cookiecutter.project_slug}}/.github/workflows/cookiecutter.yml +++ b/{{cookiecutter.project_slug}}/.github/workflows/cookiecutter.yml @@ -23,7 +23,7 @@ jobs: - name: Check if there are changes id: changes - run: echo "changed=$(git status --porcelain | wc -l)" >> $GITHUB_OUTPUT + run: echo "changed=$(git status --porcelain | wc -l)" >> $GITHUB_OUTPUT # shellcheck disable=SC2086 - name: Apply additional changes and fixes if: steps.changes.outputs.changed > 0 @@ -40,7 +40,7 @@ jobs: CURRENT_VERSION=$(git show HEAD:.cruft.json | jello -r "_['commit'][:8]") NEXT_VERSION=$(jello -r "_['commit'][:8]" < .cruft.json) echo "current_version=$CURRENT_VERSION" >> $GITHUB_OUTPUT - echo "next_version=$NEXT_VERSION" >> $GITHUB_OUTPUT + echo "next_version=$NEXT_VERSION" >> $GITHUB_OUTPUT # shellcheck disable=SC2086 - name: Get changelog id: get_changelog @@ -60,7 +60,7 @@ jobs: body="${body//'%'/'%25'}" body="${body//$'\n'/'%0A'}" body="${body//$'\r'/'%0D'}" - echo "changelog=$body" >> $GITHUB_OUTPUT + echo "changelog=$body" >> $GITHUB_OUTPUT # shellcheck disable=SC2086 # behaviour if PR already exists: https://github.com/marketplace/actions/create-pull-request#action-behaviour - name: Create Pull Request @@ -68,7 +68,7 @@ jobs: # a PAT is required to be able to update workflows GITHUB_TOKEN: ${{ secrets.AUTO_UPDATE_GITHUB_TOKEN }} if: ${{ steps.changes.outputs.changed > 0 && env.GITHUB_TOKEN != 0 }} - uses: peter-evans/create-pull-request@v5 + uses: peter-evans/create-pull-request@v6 with: token: ${{ env.GITHUB_TOKEN }} commit-message: >- diff --git a/{{cookiecutter.project_slug}}/.github/workflows/dependencies.yml b/{{cookiecutter.project_slug}}/.github/workflows/dependencies.yml index 84109a6..6a0c234 100644 --- a/{{cookiecutter.project_slug}}/.github/workflows/dependencies.yml +++ b/{{cookiecutter.project_slug}}/.github/workflows/dependencies.yml @@ -23,7 +23,7 @@ jobs: run: | body=$(uv pip list --outdated --format json) if [ "$body" != "[]" ]; then - echo "body=$body" >> $GITHUB_OUTPUT + echo "body=$body" >> $GITHUB_OUTPUT # shellcheck disable=SC2086 fi - name: Format PR Message @@ -41,7 +41,7 @@ jobs: body="${body//'%'/'%25'}" body="${body//$'\n'/'%0A'}" body="${body//$'\r'/'%0D'}" - echo "body=$body" >> $GITHUB_OUTPUT + echo "body=$body" >> $GITHUB_OUTPUT # shellcheck disable=SC2086 - name: Update outdated packages if: ${{ steps.check_for_outdated_dependencies.outputs.body != 0 }} @@ -52,7 +52,7 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} if: ${{ steps.check_for_outdated_dependencies.outputs.body != 0 }} - uses: peter-evans/create-pull-request@v5 + uses: peter-evans/create-pull-request@v6 with: token: ${{ env.GITHUB_TOKEN }} commit-message: >- From 4e1dae1cb553fb06a5fd390b0739bc05e6ecd183 Mon Sep 17 00:00:00 2001 From: Szymon Cader Date: Sun, 22 Mar 2026 10:53:45 +0100 Subject: [PATCH 15/17] Fix shellcheck SC2086 by quoting $GITHUB_OUTPUT - Quote $GITHUB_OUTPUT variable in all workflow files - Remove unnecessary shellcheck disable comments - Simplest solution that satisfies shellcheck --- .../.github/workflows/cookiecutter.yml | 8 ++++---- .../.github/workflows/dependencies.yml | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/{{cookiecutter.project_slug}}/.github/workflows/cookiecutter.yml b/{{cookiecutter.project_slug}}/.github/workflows/cookiecutter.yml index dd211a7..c9cee19 100644 --- a/{{cookiecutter.project_slug}}/.github/workflows/cookiecutter.yml +++ b/{{cookiecutter.project_slug}}/.github/workflows/cookiecutter.yml @@ -23,7 +23,7 @@ jobs: - name: Check if there are changes id: changes - run: echo "changed=$(git status --porcelain | wc -l)" >> $GITHUB_OUTPUT # shellcheck disable=SC2086 + run: echo "changed=$(git status --porcelain | wc -l)" >> "$GITHUB_OUTPUT" - name: Apply additional changes and fixes if: steps.changes.outputs.changed > 0 @@ -39,8 +39,8 @@ jobs: run: | CURRENT_VERSION=$(git show HEAD:.cruft.json | jello -r "_['commit'][:8]") NEXT_VERSION=$(jello -r "_['commit'][:8]" < .cruft.json) - echo "current_version=$CURRENT_VERSION" >> $GITHUB_OUTPUT - echo "next_version=$NEXT_VERSION" >> $GITHUB_OUTPUT # shellcheck disable=SC2086 + echo "current_version=$CURRENT_VERSION" >> "$GITHUB_OUTPUT" + echo "next_version=$NEXT_VERSION" >> "$GITHUB_OUTPUT" - name: Get changelog id: get_changelog @@ -60,7 +60,7 @@ jobs: body="${body//'%'/'%25'}" body="${body//$'\n'/'%0A'}" body="${body//$'\r'/'%0D'}" - echo "changelog=$body" >> $GITHUB_OUTPUT # shellcheck disable=SC2086 + echo "changelog=$body" >> "$GITHUB_OUTPUT" # behaviour if PR already exists: https://github.com/marketplace/actions/create-pull-request#action-behaviour - name: Create Pull Request diff --git a/{{cookiecutter.project_slug}}/.github/workflows/dependencies.yml b/{{cookiecutter.project_slug}}/.github/workflows/dependencies.yml index 6a0c234..ecad5b4 100644 --- a/{{cookiecutter.project_slug}}/.github/workflows/dependencies.yml +++ b/{{cookiecutter.project_slug}}/.github/workflows/dependencies.yml @@ -23,7 +23,7 @@ jobs: run: | body=$(uv pip list --outdated --format json) if [ "$body" != "[]" ]; then - echo "body=$body" >> $GITHUB_OUTPUT # shellcheck disable=SC2086 + echo "body=$body" >> "$GITHUB_OUTPUT" fi - name: Format PR Message @@ -41,7 +41,7 @@ jobs: body="${body//'%'/'%25'}" body="${body//$'\n'/'%0A'}" body="${body//$'\r'/'%0D'}" - echo "body=$body" >> $GITHUB_OUTPUT # shellcheck disable=SC2086 + echo "body=$body" >> "$GITHUB_OUTPUT" - name: Update outdated packages if: ${{ steps.check_for_outdated_dependencies.outputs.body != 0 }} From 8b8d0a799e2a70bba2f5e4915d2a6e6d5ebb4780 Mon Sep 17 00:00:00 2001 From: Szymon Cader Date: Sun, 22 Mar 2026 11:17:42 +0100 Subject: [PATCH 16/17] Fix workflow templating, PyPI publish auth, and hatch package config --- .../.github/workflows/dependencies.yml | 2 ++ .../.github/workflows/draft_release.yml | 2 ++ {{cookiecutter.project_slug}}/.github/workflows/release.yml | 4 ++++ {{cookiecutter.project_slug}}/pyproject.toml | 3 +++ 4 files changed, 11 insertions(+) diff --git a/{{cookiecutter.project_slug}}/.github/workflows/dependencies.yml b/{{cookiecutter.project_slug}}/.github/workflows/dependencies.yml index ecad5b4..81853e6 100644 --- a/{{cookiecutter.project_slug}}/.github/workflows/dependencies.yml +++ b/{{cookiecutter.project_slug}}/.github/workflows/dependencies.yml @@ -13,7 +13,9 @@ jobs: uses: astral-sh/setup-uv@v7 with: enable-cache: false +{% endraw %} python-version: "{{ cookiecutter._python_version_specs[cookiecutter.python_version]['versions'][0] }}" +{% raw %} - name: Install tabulate run: uv pip install tabulate diff --git a/{{cookiecutter.project_slug}}/.github/workflows/draft_release.yml b/{{cookiecutter.project_slug}}/.github/workflows/draft_release.yml index 6225050..51c49e5 100644 --- a/{{cookiecutter.project_slug}}/.github/workflows/draft_release.yml +++ b/{{cookiecutter.project_slug}}/.github/workflows/draft_release.yml @@ -17,7 +17,9 @@ jobs: uses: astral-sh/setup-uv@v7 with: enable-cache: false +{% endraw %} python-version: "{{ cookiecutter._python_version_specs[cookiecutter.python_version]['versions'][0] }}" +{% raw %} - name: Update version id: updated_version shell: bash diff --git a/{{cookiecutter.project_slug}}/.github/workflows/release.yml b/{{cookiecutter.project_slug}}/.github/workflows/release.yml index 4913c3e..aee386f 100644 --- a/{{cookiecutter.project_slug}}/.github/workflows/release.yml +++ b/{{cookiecutter.project_slug}}/.github/workflows/release.yml @@ -13,8 +13,12 @@ jobs: uses: astral-sh/setup-uv@v7 with: enable-cache: false +{% endraw %} python-version: "{{ cookiecutter._python_version_specs[cookiecutter.python_version]['versions'][0] }}" +{% raw %} - name: Publish to pypi + env: + UV_PUBLISH_TOKEN: ${{ secrets.PYPI_TOKEN }} run: uv publish --build - name: Deploy docs run: uv run mkdocs gh-deploy --force{% endraw +%} diff --git a/{{cookiecutter.project_slug}}/pyproject.toml b/{{cookiecutter.project_slug}}/pyproject.toml index 9fc7930..845d7b3 100644 --- a/{{cookiecutter.project_slug}}/pyproject.toml +++ b/{{cookiecutter.project_slug}}/pyproject.toml @@ -48,6 +48,9 @@ dev = [ requires = ["hatchling"] build-backend = "hatchling.build" +[tool.hatch.build.targets.wheel] +packages = ["src/{{ cookiecutter.package_name }}"] + [tool.ruff] target-version = "py{{ cookiecutter._python_version_specs[cookiecutter.python_version]['versions'][0].replace('.', '') }}" exclude = [ From d5ace47750d665ced3d0b810f6c3a224a4787568 Mon Sep 17 00:00:00 2001 From: Szymon Cader Date: Sun, 22 Mar 2026 11:31:21 +0100 Subject: [PATCH 17/17] fix(ci): restore uv-based workflow behavior --- .../.github/workflows/cookiecutter.yml | 6 ++++++ .../.github/workflows/dependencies.yml | 7 +++++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/{{cookiecutter.project_slug}}/.github/workflows/cookiecutter.yml b/{{cookiecutter.project_slug}}/.github/workflows/cookiecutter.yml index c9cee19..9c72837 100644 --- a/{{cookiecutter.project_slug}}/.github/workflows/cookiecutter.yml +++ b/{{cookiecutter.project_slug}}/.github/workflows/cookiecutter.yml @@ -25,6 +25,12 @@ jobs: id: changes run: echo "changed=$(git status --porcelain | wc -l)" >> "$GITHUB_OUTPUT" + - name: Install uv + if: steps.changes.outputs.changed > 0 + uses: astral-sh/setup-uv@v7 + with: + enable-cache: false + - name: Apply additional changes and fixes if: steps.changes.outputs.changed > 0 run: | diff --git a/{{cookiecutter.project_slug}}/.github/workflows/dependencies.yml b/{{cookiecutter.project_slug}}/.github/workflows/dependencies.yml index 81853e6..e6d710d 100644 --- a/{{cookiecutter.project_slug}}/.github/workflows/dependencies.yml +++ b/{{cookiecutter.project_slug}}/.github/workflows/dependencies.yml @@ -17,13 +17,16 @@ jobs: python-version: "{{ cookiecutter._python_version_specs[cookiecutter.python_version]['versions'][0] }}" {% raw %} + - name: Sync project dependencies + run: uv sync + - name: Install tabulate - run: uv pip install tabulate + run: python -m pip install tabulate - name: Gather outdated dependencies id: check_for_outdated_dependencies run: | - body=$(uv pip list --outdated --format json) + body=$(uv pip list --outdated --format json --python .venv/bin/python) if [ "$body" != "[]" ]; then echo "body=$body" >> "$GITHUB_OUTPUT" fi