Repository: scverse/cookiecutter-scverse
Pull request #373: Use hatch in github actions
Author: login: scverse-bot
Created: 2025-03-24T20:05:25Z | Merged: 2025-03-27T09:50:07Z

This is an attempt to move all CI scripts to `hatch` wherever possible. Not sure if we want that in all cases, but at least for running `pytest` it makes sense as it simplifies the CI script quite a bit and the `pyproject.toml` becomes the single point of truth on how to run tests. 

- [ ] implement dependency groups according to [PEP735](https://packaging.python.org/en/latest/specifications/dependency-groups/#dependency-groups)

Cheers, 
@grst 


Diff:
diff --git a/.github/workflows/cruft-prs.yml b/.github/workflows/cruft-prs.yml
index bee1ab69..159ec67b 100644
--- a/.github/workflows/cruft-prs.yml
+++ b/.github/workflows/cruft-prs.yml
@@ -30,7 +30,7 @@ jobs:
           GITHUB_TOKEN: ${{ secrets.BOT_GH_TOKEN }}
           FORCE_COLOR: "1"
           COLUMNS: "150"
-      - uses: actions/upload-artifact@v3
+      - uses: actions/upload-artifact@v4
         with:
           name: cruft-logs
           path: log/
diff --git a/.github/workflows/deploy-instance-repo.yml b/.github/workflows/deploy-instance-repo.yml
index 4ac900f5..7d4be47d 100644
--- a/.github/workflows/deploy-instance-repo.yml
+++ b/.github/workflows/deploy-instance-repo.yml
@@ -44,7 +44,7 @@ jobs:
 
       - name: Build from template
         run: |
-          uv tool run --with pre-commit cruft create \
+          uvx --with pre-commit cruft create \
             --no-input \
             --output-dir $INSTANCE_GENERATED \
             --extra-context-file .github/assets/cookiecutter-scverse-instance.json \
diff --git a/.github/workflows/propagate-pre-commit.yml b/.github/workflows/propagate-pre-commit.yml
index 404e9378..b195d84b 100644
--- a/.github/workflows/propagate-pre-commit.yml
+++ b/.github/workflows/propagate-pre-commit.yml
@@ -9,7 +9,7 @@ jobs:
   update:
     runs-on: ubuntu-latest
     steps:
-      - uses: actions/checkout@v3
+      - uses: actions/checkout@v4
         with:
           token: ${{ secrets.BOT_GH_TOKEN }}
       - run: pipx install pre-commit
diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml
index c104db9e..55d2922b 100644
--- a/.github/workflows/test.yaml
+++ b/.github/workflows/test.yaml
@@ -73,17 +73,12 @@ jobs:
     runs-on: ubuntu-latest
     steps:
       - uses: actions/checkout@v4
-      - name: Set up Python 3.11
-        uses: actions/setup-python@v5
+      - name: Install uv
+        uses: astral-sh/setup-uv@v5
         with:
-          python-version: "3.11"
-          cache: "pip"
-          cache-dependency-path: "**/pyproject.toml"
-      - name: set python default branch
+          cache-dependency-glob: pyproject.toml
+      - name: set git default branch
         run: git config --global init.defaultBranch main
-      - name: Install build dependencies
-        run: python -m pip install --upgrade pip wheel
-      - name: Install package
-        run: pip install ./scripts[test]
       - name: Run tests
-        run: pytest -v --color=yes ./scripts
+        working-directory: ./scripts
+        run: uvx hatch test
diff --git a/README.md b/README.md
index f48d0097..4a41daa8 100644
--- a/README.md
+++ b/README.md
@@ -61,7 +61,7 @@ To create the project, run the following command and follow the prompts:
 
 ```bash
 # uv will download all dependencies on-the-fly
-uv tool run --with pre-commit cruft create https://github.com/scverse/cookiecutter-scverse
+uvx --with pre-commit cruft create https://github.com/scverse/cookiecutter-scverse
 ```
 
 This will create a git repository generated from the template.
diff --git a/hooks/post_gen_project.py b/hooks/post_gen_project.py
index 3f1f79ee..5ae73b63 100644
--- a/hooks/post_gen_project.py
+++ b/hooks/post_gen_project.py
@@ -22,8 +22,7 @@ def skipped_dirs():
     assert path.is_dir(), path
     shutil.rmtree(path)
 
-# Update pre commit hooks
-run("pre-commit autoupdate -c .pre-commit-config.yaml".split(), check=True)
+# Insatll pre-commit
 run("pre-commit install".split(), check=True)
 
 # The following output was generated using rich
diff --git a/{{cookiecutter.project_name}}/.github/workflows/build.yaml b/{{cookiecutter.project_name}}/.github/workflows/build.yaml
index bfa2cf00..e822177a 100644
--- a/{{cookiecutter.project_name}}/.github/workflows/build.yaml
+++ b/{{cookiecutter.project_name}}/.github/workflows/build.yaml
@@ -10,20 +10,23 @@ concurrency:
   group: ${{ github.workflow }}-${{ github.ref }}
   cancel-in-progress: true
 
+defaults:
+  run:
+    shell: bash -e {0} # -e to fail on error
+
 jobs:
   package:
     runs-on: ubuntu-latest
     steps:
       - uses: actions/checkout@v4
-      - name: Set up Python 3.12
-        uses: actions/setup-python@v5
         with:
-          python-version: "3.12"
-          cache: "pip"
-          cache-dependency-path: "**/pyproject.toml"
-      - name: Install build dependencies
-        run: python -m pip install --upgrade pip wheel twine build
+          filter: blob:none
+          fetch-depth: 0
+      - name: Install uv
+        uses: astral-sh/setup-uv@v5
+        with:
+          cache-dependency-glob: pyproject.toml
       - name: Build package
-        run: python -m build
+        run: uv build
       - name: Check package
-        run: twine check --strict dist/*.whl
+        run: uvx twine check --strict dist/*.whl
diff --git a/{{cookiecutter.project_name}}/.github/workflows/release.yaml b/{{cookiecutter.project_name}}/.github/workflows/release.yaml
index 809a3c1f..7ad02f85 100644
--- a/{{cookiecutter.project_name}}/.github/workflows/release.yaml
+++ b/{{cookiecutter.project_name}}/.github/workflows/release.yaml
@@ -4,6 +4,10 @@ on:
   release:
     types: [published]
 
+defaults:
+  run:
+    shell: bash -e {0} # -e to fail on error
+
 # Use "trusted publishing", see https://docs.pypi.org/trusted-publishers/
 jobs:
   release:
@@ -19,11 +23,11 @@ jobs:
         with:
           filter: blob:none
           fetch-depth: 0
-      - uses: actions/setup-python@v5
+      - name: Install uv
+        uses: astral-sh/setup-uv@v5
         with:
-          python-version: "3.x"
-          cache: "pip"
-      - run: pip install build
-      - run: python -m build
+          cache-dependency-glob: pyproject.toml
+      - name: Build package
+        run: uv build
       - name: Publish package distributions to PyPI
         uses: pypa/gh-action-pypi-publish@release/v1
diff --git a/{{cookiecutter.project_name}}/.github/workflows/test.yaml b/{{cookiecutter.project_name}}/.github/workflows/test.yaml
index 841bd7c2..fccf2abc 100644
--- a/{{cookiecutter.project_name}}/.github/workflows/test.yaml
+++ b/{{cookiecutter.project_name}}/.github/workflows/test.yaml
@@ -12,12 +12,13 @@ concurrency:
   group: ${{ github.workflow }}-${{ github.ref }}
   cancel-in-progress: true
 
+defaults:
+  run:
+    shell: bash -e {0} # -e to fail on error
+
 jobs:
   test:
     runs-on: ${{ matrix.os }}
-    defaults:
-      run:
-        shell: bash -e {0} # -e to fail on error
 
     strategy:
       fail-fast: false
@@ -40,28 +41,18 @@ jobs:
 
     steps:
       - uses: actions/checkout@v4
-      - name: Set up Python ${{ matrix.python }}
-        uses: actions/setup-python@v5
         with:
-          python-version: ${{ matrix.python }}
-          cache: "pip"
-          cache-dependency-path: "**/pyproject.toml"
-
-      - name: Install test dependencies
-        run: |
-          python -m pip install --upgrade pip wheel
-      - name: Install dependencies
-        run: |
-          pip install ${{ matrix.pip-flags }} ".[dev,test]"
-      - name: Test
+          filter: blob:none
+          fetch-depth: 0
+      - name: Install uv
+        uses: astral-sh/setup-uv@v5
+        with:
+          cache-dependency-glob: pyproject.toml
+      - name: run tests using hatch
         env:
           MPLBACKEND: agg
           PLATFORM: ${{ matrix.os }}
           DISPLAY: :42
-        run: |
-          coverage run -m pytest -v --color=yes
-      - name: Report coverage
-        run: |
-          coverage report
+        run: uvx hatch test --cover --python ${{ matrix.python }}
       - name: Upload coverage
-        uses: codecov/codecov-action@v3
+        uses: codecov/codecov-action@v4


Reviews:
user: login: grst
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-03-24T20:13:44Z
user: login: Zethson
body: Great!

I think @flying-sheep should ultimately approve this.

Generally, we are now really all-in on Hatch and I would not be surprised if `uv` expanded its scope in a year or two and we go all in on `uv`. It's still okay with me to commit more to Hatch now because well, we already use it in so many parts.
state: APPROVED
author_association: MEMBER
submitted_at: 2025-03-25T08:55:50Z
user: login: flying-sheep
body: Looking good, this certainly deduplicates things conceptually and makes everything easier to grasp.

The following collapsed section is #374

<details>
<summary>Details</summary>

Before I start: The “changes requested” is basically only because this PR should also get rid of the `doc` and `test` extras and move the doc deps and test deps into the respective hatch env configs. These extras are artifacts of using standard tooling in CI, and there is no need to expose them to users of the package when using Hatch in CI[^1].

[^1]: There is discussion about introducing the concept of dev dependencies to standard Python project metadata: [PEP 735](https://peps.python.org/pep-0735/). Until then, when a package wants to export a test utilities subpackage (e.g. `testing.mypackage` or `mypackage.testing` or so), the package can define a `testing` extra for users and use it from Hatch together with `envs.hatch-test.dependencies` like `envs.hatch-test.features = ["testing"]`. 

</details>

OK: there are two schools of thought here:
1. Before this PR: stick with standard tooling throughout everything to minimize lock-in with the build tool and keep things as simple as possible[^2].
2. This PR: keep local development as close to what happens in CI

[^2]: Note that I use “simple” in the same way a VW Beetle or Arch Linux are simple: “Use the most standard set of parts possible so everything is maximally debuggable when things break”

I think both approaches are valid. So this PR will make things as close to a local dev environment as possible at the cost of being slightly less debuggable if they break, e.g. there are now two environments in CI (system and hatch-test), not just the system one, but people should be used to that anyway.
state: CHANGES_REQUESTED
author_association: MEMBER
submitted_at: 2025-03-25T09:00:25Z
user: login: grst
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-03-27T09:05:45Z
user: login: grst
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-03-27T09:06:29Z
user: login: flying-sheep
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-27T09:16:19Z
user: login: flying-sheep
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-27T09:17:57Z
user: login: grst
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-03-27T09:20:38Z
user: login: grst
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-03-27T09:21:33Z
user: login: flying-sheep
state: APPROVED
author_association: MEMBER
submitted_at: 2025-03-27T09:31:50Z

Review comments:
diff_hunk: @@ -19,11 +19,8 @@ jobs:
         with:
           filter: blob:none
           fetch-depth: 0
-      - uses: actions/setup-python@v5
-        with:
-          python-version: "3.x"
-          cache: "pip"
-      - run: pip install build
-      - run: python -m build
+      - name: Install Hatch
+        uses: pypa/hatch@install
+      - run: hatch build
path: {{cookiecutter.project_name}}/.github/workflows/release.yaml
user: login: grst
body: Not sure if we have a good reason to switch to hatch here, but it would be possible. 
created_at: 2025-03-24T20:08:14Z
author_association: COLLABORATOR
diff_hunk: @@ -40,28 +40,13 @@ jobs:
 
     steps:
       - uses: actions/checkout@v4
-      - name: Set up Python ${{ matrix.python }}
-        uses: actions/setup-python@v5
-        with:
-          python-version: ${{ matrix.python }}
-          cache: "pip"
-          cache-dependency-path: "**/pyproject.toml"
-
-      - name: Install test dependencies
-        run: |
-          python -m pip install --upgrade pip wheel
-      - name: Install dependencies
-        run: |
-          pip install ${{ matrix.pip-flags }} ".[dev,test]"
-      - name: Test
+      - name: Install Hatch
+        uses: pypa/hatch@install
+      - name: run tests using hatch
         env:
           MPLBACKEND: agg
           PLATFORM: ${{ matrix.os }}
           DISPLAY: :42
-        run: |
-          coverage run -m pytest -v --color=yes
-      - name: Report coverage
-        run: |
-          coverage report
+        run: hatch test --cover --python ${{ matrix.python }}
path: {{cookiecutter.project_name}}/.github/workflows/test.yaml
user: login: grst
body: Allegedly this creates a coverage report, so the `coverage report` command would not be needed. 
created_at: 2025-03-24T20:08:52Z
author_association: COLLABORATOR
diff_hunk: @@ -15,15 +15,12 @@ jobs:
     runs-on: ubuntu-latest
     steps:
       - uses: actions/checkout@v4
-      - name: Set up Python 3.12
-        uses: actions/setup-python@v5
         with:
-          python-version: "3.12"
-          cache: "pip"
-          cache-dependency-path: "**/pyproject.toml"
-      - name: Install build dependencies
-        run: python -m pip install --upgrade pip wheel twine build
+          filter: blob:none
+          fetch-depth: 0
+      - name: Install the latest version of uv
+        uses: astral-sh/setup-uv@v5
path: {{cookiecutter.project_name}}/.github/workflows/build.yaml
user: login: grst
body: I used `uv` instead of `hatch` here for the sake of running `twine check` separately
created_at: 2025-03-24T20:09:40Z
author_association: COLLABORATOR
diff_hunk: @@ -15,15 +15,12 @@ jobs:
     runs-on: ubuntu-latest
     steps:
       - uses: actions/checkout@v4
-      - name: Set up Python 3.12
-        uses: actions/setup-python@v5
         with:
-          python-version: "3.12"
-          cache: "pip"
-          cache-dependency-path: "**/pyproject.toml"
-      - name: Install build dependencies
-        run: python -m pip install --upgrade pip wheel twine build
+          filter: blob:none
+          fetch-depth: 0
path: {{cookiecutter.project_name}}/.github/workflows/build.yaml
user: login: grst
body: Should we include filter: `blob:none` by default in all action scripts or rather stick with the default shallow checkout? 
created_at: 2025-03-24T20:13:29Z
author_association: COLLABORATOR
diff_hunk: @@ -73,17 +73,10 @@ jobs:
     runs-on: ubuntu-latest
     steps:
       - uses: actions/checkout@v4
-      - name: Set up Python 3.11
-        uses: actions/setup-python@v5
-        with:
-          python-version: "3.11"
-          cache: "pip"
-          cache-dependency-path: "**/pyproject.toml"
-      - name: set python default branch
+      - name: Install Hatch
+        uses: pypa/hatch@install
+      - name: set git  default branch
path: .github/workflows/test.yaml
user: login: flying-sheep
body: ```suggestion
      - name: set git default branch
```
created_at: 2025-03-25T08:27:56Z
author_association: MEMBER
diff_hunk: @@ -15,15 +15,12 @@ jobs:
     runs-on: ubuntu-latest
     steps:
       - uses: actions/checkout@v4
-      - name: Set up Python 3.12
-        uses: actions/setup-python@v5
         with:
-          python-version: "3.12"
-          cache: "pip"
-          cache-dependency-path: "**/pyproject.toml"
-      - name: Install build dependencies
-        run: python -m pip install --upgrade pip wheel twine build
+          filter: blob:none
+          fetch-depth: 0
path: {{cookiecutter.project_name}}/.github/workflows/build.yaml
user: login: flying-sheep
body: As far as I can tell, `filter: blob:none` is simply a better default. There are scenarios where one would want to do a full clone, but I can’t think of a scenario where `fetch-depth: 1` would be in any way preferable.
created_at: 2025-03-25T08:32:16Z
author_association: MEMBER
diff_hunk: @@ -15,15 +15,12 @@ jobs:
     runs-on: ubuntu-latest
     steps:
       - uses: actions/checkout@v4
-      - name: Set up Python 3.12
-        uses: actions/setup-python@v5
         with:
-          python-version: "3.12"
-          cache: "pip"
-          cache-dependency-path: "**/pyproject.toml"
-      - name: Install build dependencies
-        run: python -m pip install --upgrade pip wheel twine build
+          filter: blob:none
+          fetch-depth: 0
+      - name: Install the latest version of uv
+        uses: astral-sh/setup-uv@v5
path: {{cookiecutter.project_name}}/.github/workflows/build.yaml
user: login: flying-sheep
body: Makes sense! I think this will warn that the lockfile glob doesn’t match, so maybe disable the cache here?
created_at: 2025-03-25T08:34:02Z
author_association: MEMBER
diff_hunk: @@ -15,15 +15,12 @@ jobs:
     runs-on: ubuntu-latest
     steps:
       - uses: actions/checkout@v4
-      - name: Set up Python 3.12
-        uses: actions/setup-python@v5
         with:
-          python-version: "3.12"
-          cache: "pip"
-          cache-dependency-path: "**/pyproject.toml"
-      - name: Install build dependencies
-        run: python -m pip install --upgrade pip wheel twine build
+          filter: blob:none
+          fetch-depth: 0
+      - name: Install the latest version of uv
+        uses: astral-sh/setup-uv@v5
       - name: Build package
-        run: python -m build
+        run: uv tool run hatch build
path: {{cookiecutter.project_name}}/.github/workflows/build.yaml
user: login: flying-sheep
body: Maybe we should stick with `pyproject-build` here, as it’s the standard tool for the job like `twine` is, but I don’t feel strongly.

```suggestion
        run: uvx --from=build pyproject-build --installer=uv --wheel
created_at: 2025-03-25T08:34:39Z
author_association: MEMBER
diff_hunk: @@ -15,15 +15,12 @@ jobs:
     runs-on: ubuntu-latest
     steps:
       - uses: actions/checkout@v4
-      - name: Set up Python 3.12
-        uses: actions/setup-python@v5
         with:
-          python-version: "3.12"
-          cache: "pip"
-          cache-dependency-path: "**/pyproject.toml"
-      - name: Install build dependencies
-        run: python -m pip install --upgrade pip wheel twine build
+          filter: blob:none
+          fetch-depth: 0
+      - name: Install the latest version of uv
+        uses: astral-sh/setup-uv@v5
       - name: Build package
-        run: python -m build
+        run: uv tool run hatch build
       - name: Check package
-        run: twine check --strict dist/*.whl
+        run: uv tool run twine check --strict dist/*.whl
path: {{cookiecutter.project_name}}/.github/workflows/build.yaml
user: login: flying-sheep
body: ```suggestion
        run: uvx twine check --strict dist/*.whl
```
created_at: 2025-03-25T08:38:01Z
author_association: MEMBER
diff_hunk: @@ -19,11 +19,8 @@ jobs:
         with:
           filter: blob:none
           fetch-depth: 0
-      - uses: actions/setup-python@v5
-        with:
-          python-version: "3.x"
-          cache: "pip"
-      - run: pip install build
-      - run: python -m build
+      - name: Install Hatch
+        uses: pypa/hatch@install
+      - run: hatch build
path: {{cookiecutter.project_name}}/.github/workflows/release.yaml
user: login: flying-sheep
body: As said above, I probably wouldn’t use `hatch build`. If we don’t, we should use `pyproject-build --installer=uv`, which would make this very slightly faster
created_at: 2025-03-25T08:40:15Z
author_association: MEMBER
diff_hunk: @@ -40,28 +40,13 @@ jobs:
 
     steps:
       - uses: actions/checkout@v4
-      - name: Set up Python ${{ matrix.python }}
-        uses: actions/setup-python@v5
-        with:
-          python-version: ${{ matrix.python }}
-          cache: "pip"
-          cache-dependency-path: "**/pyproject.toml"
-
-      - name: Install test dependencies
-        run: |
-          python -m pip install --upgrade pip wheel
-      - name: Install dependencies
-        run: |
-          pip install ${{ matrix.pip-flags }} ".[dev,test]"
-      - name: Test
+      - name: Install Hatch
+        uses: pypa/hatch@install
+      - name: run tests using hatch
         env:
           MPLBACKEND: agg
           PLATFORM: ${{ matrix.os }}
           DISPLAY: :42
-        run: |
-          coverage run -m pytest -v --color=yes
-      - name: Report coverage
-        run: |
-          coverage report
+        run: hatch test --cover --python ${{ matrix.python }}
path: {{cookiecutter.project_name}}/.github/workflows/test.yaml
user: login: flying-sheep
body: correct!
created_at: 2025-03-25T08:41:16Z
author_association: MEMBER
diff_hunk: @@ -73,17 +73,10 @@ jobs:
     runs-on: ubuntu-latest
     steps:
       - uses: actions/checkout@v4
-      - name: Set up Python 3.11
-        uses: actions/setup-python@v5
-        with:
-          python-version: "3.11"
-          cache: "pip"
-          cache-dependency-path: "**/pyproject.toml"
-      - name: set python default branch
+      - name: Install Hatch
+        uses: pypa/hatch@install
+      - name: set git  default branch
path: .github/workflows/test.yaml
user: login: Zethson
body: ```suggestion
      - name: set git default branch
```
created_at: 2025-03-25T08:49:55Z
author_association: MEMBER
diff_hunk: @@ -73,17 +73,10 @@ jobs:
     runs-on: ubuntu-latest
     steps:
       - uses: actions/checkout@v4
-      - name: Set up Python 3.11
-        uses: actions/setup-python@v5
-        with:
-          python-version: "3.11"
-          cache: "pip"
-          cache-dependency-path: "**/pyproject.toml"
-      - name: set python default branch
+      - name: Install Hatch
+        uses: pypa/hatch@install
path: .github/workflows/test.yaml
user: login: Zethson
body: https://github.com/pypa/hatch/tree/install
Kinda weird that they don't versionize it properly but instead recommend to pin a commit. It would be better but look a bit ugly. I would hope that such a simple action is stable enough.
created_at: 2025-03-25T08:51:32Z
author_association: MEMBER
diff_hunk: @@ -15,15 +15,12 @@ jobs:
     runs-on: ubuntu-latest
     steps:
       - uses: actions/checkout@v4
-      - name: Set up Python 3.12
-        uses: actions/setup-python@v5
         with:
-          python-version: "3.12"
-          cache: "pip"
-          cache-dependency-path: "**/pyproject.toml"
-      - name: Install build dependencies
-        run: python -m pip install --upgrade pip wheel twine build
+          filter: blob:none
+          fetch-depth: 0
+      - name: Install the latest version of uv
path: {{cookiecutter.project_name}}/.github/workflows/build.yaml
user: login: Zethson
body: ```suggestion
      - name: Install uv
```

Unnecessary detail. The version is encoded just below. I would hope that it gets regular updates through dependabot or our sync :)
created_at: 2025-03-25T08:52:30Z
author_association: MEMBER
diff_hunk: @@ -15,15 +15,12 @@ jobs:
     runs-on: ubuntu-latest
     steps:
       - uses: actions/checkout@v4
-      - name: Set up Python 3.12
-        uses: actions/setup-python@v5
         with:
-          python-version: "3.12"
-          cache: "pip"
-          cache-dependency-path: "**/pyproject.toml"
-      - name: Install build dependencies
-        run: python -m pip install --upgrade pip wheel twine build
+          filter: blob:none
+          fetch-depth: 0
path: {{cookiecutter.project_name}}/.github/workflows/build.yaml
user: login: Zethson
body: I think `blob:none` is a good idea in our workflows.
created_at: 2025-03-25T08:53:47Z
author_association: MEMBER
diff_hunk: @@ -19,11 +19,8 @@ jobs:
         with:
           filter: blob:none
           fetch-depth: 0
-      - uses: actions/setup-python@v5
-        with:
-          python-version: "3.x"
-          cache: "pip"
-      - run: pip install build
-      - run: python -m build
+      - name: Install Hatch
+        uses: pypa/hatch@install
+      - run: hatch build
path: {{cookiecutter.project_name}}/.github/workflows/release.yaml
user: login: Zethson
body: Since we already go all in with hatch, it's fine with me.
created_at: 2025-03-25T08:54:25Z
author_association: MEMBER
diff_hunk: @@ -4,6 +4,10 @@ on:
   release:
     types: [published]
 
+defaults:
+  run:
+    shell: bash -e {0} # -e to fail on error
path: {{cookiecutter.project_name}}/.github/workflows/release.yaml
user: login: grst
body: Is that really necessary? I'd have thought this only affects multi-line commands in `run`. 
created_at: 2025-03-27T09:05:45Z
author_association: COLLABORATOR
diff_hunk: @@ -73,17 +73,14 @@ jobs:
     runs-on: ubuntu-latest
     steps:
       - uses: actions/checkout@v4
-      - name: Set up Python 3.11
-        uses: actions/setup-python@v5
+      - name: Install uv
+        uses: astral-sh/setup-uv@v5
         with:
-          python-version: "3.11"
-          cache: "pip"
-          cache-dependency-path: "**/pyproject.toml"
-      - name: set python default branch
+          cache-dependency-glob: pyproject.toml
+      - name: Install Hatch
+        run: uv tool install hatch
path: .github/workflows/test.yaml
user: login: grst
body: Not really important, but shall we save two more lines by using `uvx hatch test` below? 
created_at: 2025-03-27T09:06:29Z
author_association: COLLABORATOR
diff_hunk: @@ -4,6 +4,10 @@ on:
   release:
     types: [published]
 
+defaults:
+  run:
+    shell: bash -e {0} # -e to fail on error
path: {{cookiecutter.project_name}}/.github/workflows/release.yaml
user: login: flying-sheep
body: > this only affects multi-line commands in run

it does. it’ really gross that this isn’t the default, so putting it there will save a lot of people a lot of time.

nobody expects that adding a command at the bottom suddenly suppresses errors in the command above.
created_at: 2025-03-27T09:16:19Z
author_association: MEMBER
diff_hunk: @@ -73,17 +73,14 @@ jobs:
     runs-on: ubuntu-latest
     steps:
       - uses: actions/checkout@v4
-      - name: Set up Python 3.11
-        uses: actions/setup-python@v5
+      - name: Install uv
+        uses: astral-sh/setup-uv@v5
         with:
-          python-version: "3.11"
-          cache: "pip"
-          cache-dependency-path: "**/pyproject.toml"
-      - name: set python default branch
+          cache-dependency-glob: pyproject.toml
+      - name: Install Hatch
+        run: uv tool install hatch
path: .github/workflows/test.yaml
user: login: flying-sheep
body: we can totally do that
created_at: 2025-03-27T09:17:57Z
author_association: MEMBER
diff_hunk: @@ -4,6 +4,10 @@ on:
   release:
     types: [published]
 
+defaults:
+  run:
+    shell: bash -e {0} # -e to fail on error
path: {{cookiecutter.project_name}}/.github/workflows/release.yaml
user: login: grst
body: fair enough, let's be safe here. 
created_at: 2025-03-27T09:20:38Z
author_association: COLLABORATOR
diff_hunk: @@ -4,6 +4,10 @@ on:
   release:
     types: [published]
 
+defaults:
+  run:
+    shell: bash -e {0} # -e to fail on error
path: {{cookiecutter.project_name}}/.github/workflows/release.yaml
user: login: grst
body: but then shouldn't we go all in with `-euo pipefail` or at least `-eo pipefail`? 
created_at: 2025-03-27T09:21:33Z
author_association: COLLABORATOR

PR comments:
user: login: github-actions[bot]
created_at: 2025-03-24T20:05:46Z
body: A PR has been generated to the instance repo:
https://github.com/scverse/cookiecutter-scverse-instance/pull/186


You can check out the PR to preview your changes
in an instance of the cookiecutter template. The PR will be kept in sync with
this PR automatically.
author_association: NONE
user: login: flying-sheep
created_at: 2025-03-25T08:27:13Z
body: ![grafik](https://github.com/user-attachments/assets/93e3de31-6328-4a81-8e7c-2cefd2df375d)

also a good reason to use an app instead of a bot account
author_association: MEMBER
user: login: flying-sheep
created_at: 2025-03-25T09:12:35Z
body: @Zethson see #331

> I would not be surprised if uv expanded its scope in a year or two and we go all in on uv.

Hatch is currently by far the best environment manager (i.e. alternative to tox), this is why we use it. So keep in mind that unless uv expands into that territory, it’s no alternative to what we use Hatch for IMHO.
author_association: MEMBER
user: login: flying-sheep
created_at: 2025-03-27T08:55:34Z
body: OK, I made #375 for an alternative approach, let’s discuss there!
author_association: MEMBER
user: login: flying-sheep
created_at: 2025-03-27T09:31:41Z
body: I’m a bit confused why tests fail here. The `.pre-commit-config.yaml` contains `biome` tagged to 1.9.4, so why is 2.0.0b1 used here?

Apart from this, I think this looks great!
author_association: MEMBER
user: login: grst
created_at: 2025-03-27T09:41:35Z
body: > I’m a bit confused why tests fail here. The .pre-commit-config.yaml contains biome tagged to 1.9.4, so why is 2.0.0b1 used here?

I don't get it either. The [package-lock.json](https://github.com/biomejs/pre-commit/blob/v1.9.4/package-lock.json) of the v1.9.4 release seems to pin the correct package versions. Is `pre-commit` doing something weird? 
author_association: COLLABORATOR
user: login: flying-sheep
created_at: 2025-03-27T09:43:49Z
body: Ah I got it, we’re asking for that. (I mean, yeah, the fact that pre-commit updates to pre-releases is weird, but nothing new)

https://github.com/scverse/cookiecutter-scverse/blob/a274031218a69f67a8b288f2a5efc7d16b125f0c/hooks/post_gen_project.py#L26

Maybe we should stop doing that? We keep the template updated nicely at all times anyway
author_association: MEMBER
user: login: grst
created_at: 2025-03-27T09:45:27Z
body: > Maybe we should stop doing that? We keep the template updated nicely at all times anyway

agree, let's get rid of it
author_association: COLLABORATOR