Skip to content

Commit ac0ec79

Browse files
committed
build: migrate from pip to uv for dependency management
## What Replace pip-based dependency management with uv across the entire project: pyproject.toml and uv.lock replace requirements.txt and requirements-test.txt, all CI workflows use astral-sh/setup-uv, Makefile commands prefixed with uv run, and Dockerfile uses uv for production installs. ## Why uv provides significantly faster dependency resolution and installation, deterministic lockfile-based builds, and a single pyproject.toml as the source of truth for all dependencies. This aligns with the approach already adopted by the contributors and cleanowners repos. ## Notes - CI matrix expanded to Python 3.11-3.14 - New update-uv-lock.yml workflow handles Dependabot PR lockfile sync - Docker image copies uv binary from ghcr.io/astral-sh/uv:0.10.9 - Added .codespellrc to ignore "astroid" (pylint dependency) - Added .venv to .jscpd.json ignore list Signed-off-by: jmeridth <jmeridth@gmail.com>
1 parent 9a21b81 commit ac0ec79

13 files changed

Lines changed: 1048 additions & 80 deletions

.github/linters/.codespellrc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
[codespell]
2+
ignore-words-list = astroid

.github/linters/.jscpd.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
22
"threshold": 25,
3-
"ignore": ["test*"],
3+
"ignore": ["test*", "**/.venv/**"],
44
"absolute": true
55
}

.github/workflows/copilot-setup-steps.yml

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,11 @@ jobs:
3030
with:
3131
persist-credentials: false
3232

33-
- name: Set up Python
34-
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
35-
with:
36-
python-version: 3.12
33+
- name: Install uv
34+
uses: astral-sh/setup-uv@0c5e2b8115b80b4c7c5ddf6ffdd634974642d182 # v5.4.1
35+
36+
- name: Install Python
37+
run: uv python install 3.14
3738

3839
- name: Install dependencies
39-
run: |
40-
pip install -r requirements.txt -r requirements-test.txt
40+
run: uv sync --frozen --python 3.14

.github/workflows/linter.yaml

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,10 @@ jobs:
2424
# list of changed files within `super-linter`
2525
fetch-depth: 0
2626
persist-credentials: false
27-
- name: Setup Python
28-
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
29-
with:
30-
python-version: "3.12"
27+
- name: Install uv
28+
uses: astral-sh/setup-uv@0c5e2b8115b80b4c7c5ddf6ffdd634974642d182 # v5.4.1
3129
- name: Install dependencies
32-
run: |
33-
python -m pip install --upgrade pip
34-
pip install -r requirements.txt -r requirements-test.txt
30+
run: uv sync --frozen
3531
- name: Lint Code Base
3632
uses: super-linter/super-linter@61abc07d755095a68f4987d1c2c3d1d64408f1f9 # v8.5.0
3733
env:

.github/workflows/python-package.yml

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,19 +17,17 @@ jobs:
1717
runs-on: ubuntu-latest
1818
strategy:
1919
matrix:
20-
python-version: [3.11, 3.12, 3.13]
20+
python-version: [3.11, 3.12, 3.13, 3.14]
2121
steps:
2222
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
2323
with:
2424
persist-credentials: false
25-
- name: Set up Python ${{ matrix.python-version }}
26-
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
27-
with:
28-
python-version: ${{ matrix.python-version }}
25+
- name: Install uv
26+
uses: astral-sh/setup-uv@0c5e2b8115b80b4c7c5ddf6ffdd634974642d182 # v5.4.1
27+
- name: Install Python ${{ matrix.python-version }}
28+
run: uv python install ${{ matrix.python-version }}
2929
- name: Install dependencies
30-
run: |
31-
python -m pip install --upgrade pip
32-
pip install -r requirements.txt -r requirements-test.txt
30+
run: uv sync --frozen --python ${{ matrix.python-version }}
3331
- name: Lint with flake8 and pylint
3432
run: |
3533
make lint
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
---
2+
name: Update uv.lock
3+
4+
on:
5+
pull_request:
6+
paths:
7+
- pyproject.toml
8+
9+
permissions:
10+
contents: write
11+
pull-requests: write
12+
13+
jobs:
14+
update-lock:
15+
if: github.event.pull_request.user.login == 'dependabot[bot]'
16+
runs-on: ubuntu-latest
17+
steps:
18+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
19+
with:
20+
ref: ${{ github.head_ref }}
21+
persist-credentials: true
22+
23+
- name: Install uv
24+
uses: astral-sh/setup-uv@0c5e2b8115b80b4c7c5ddf6ffdd634974642d182 # v5.4.1
25+
26+
- name: Update uv.lock
27+
run: uv lock
28+
29+
- name: Commit updated lockfile
30+
run: |
31+
git config user.name "github-actions[bot]"
32+
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
33+
git add uv.lock
34+
git diff --cached --quiet || git commit -s -m "chore(deps): update uv.lock"
35+
git push

Dockerfile

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,11 @@ LABEL com.github.actions.name="stale-repos" \
1414
org.opencontainers.image.description="Find stale repositories in a GitHub organization."
1515

1616
WORKDIR /action/workspace
17-
COPY requirements.txt *.py /action/workspace/
17+
COPY pyproject.toml uv.lock *.py /action/workspace/
1818

19-
RUN python3 -m pip install --no-cache-dir --no-deps -r requirements.txt \
19+
COPY --from=ghcr.io/astral-sh/uv:0.10.9@sha256:10902f58a1606787602f303954cea099626a4adb02acbac4c69920fe9d278f82 /uv /uvx /bin/
20+
21+
RUN uv sync --frozen --no-dev --no-editable \
2022
&& apt-get -y update \
2123
&& apt-get -y install --no-install-recommends git=1:2.47.3-0+deb13u1 \
2224
&& rm -rf /var/lib/apt/lists/*
@@ -25,5 +27,6 @@ RUN python3 -m pip install --no-cache-dir --no-deps -r requirements.txt \
2527
HEALTHCHECK --interval=30s --timeout=10s --start-period=10s --retries=3 \
2628
CMD python3 -c "import os,sys; sys.exit(0 if os.path.exists('/action/workspace/stale_repos.py') else 1)"
2729

30+
ENV PYTHONUNBUFFERED=1
2831
CMD ["/action/workspace/stale_repos.py"]
29-
ENTRYPOINT ["python3", "-u"]
32+
ENTRYPOINT ["uv", "run"]

Makefile

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
.PHONY: test
22
test:
3-
pytest -v --cov=. --cov-config=.coveragerc --cov-fail-under=80 --cov-report term-missing
3+
uv run pytest -v --cov=. --cov-config=.coveragerc --cov-fail-under=80 --cov-report term-missing
44

55
.PHONY: clean
66
clean:
@@ -9,10 +9,10 @@ clean:
99
.PHONY: lint
1010
lint:
1111
# stop the build if there are Python syntax errors or undefined names
12-
flake8 . --config=.github/linters/.flake8 --count --select=E9,F63,F7,F82 --show-source
12+
uv run flake8 . --config=.github/linters/.flake8 --count --select=E9,F63,F7,F82 --show-source
1313
# exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
14-
flake8 . --config=.github/linters/.flake8 --count --exit-zero --max-complexity=15 --max-line-length=150
15-
isort --settings-file=.github/linters/.isort.cfg .
16-
pylint --rcfile=.github/linters/.python-lint --fail-under=9.0 *.py
17-
mypy --config-file=.github/linters/.mypy.ini *.py
18-
black .
14+
uv run flake8 . --config=.github/linters/.flake8 --count --exit-zero --max-complexity=15 --max-line-length=150
15+
uv run isort --settings-file=.github/linters/.isort.cfg .
16+
uv run pylint --rcfile=.github/linters/.python-lint --fail-under=9.0 *.py
17+
uv run mypy --config-file=.github/linters/.mypy.ini *.py
18+
uv run black .

README.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -305,19 +305,21 @@ jobs:
305305
## Local usage without Docker
306306
307307
1. Have Python v3.11 or greater installed
308+
1. [Install uv](https://docs.astral.sh/uv/getting-started/installation/)
308309
1. Copy `.env-example` to `.env`
309310
1. Fill out the `.env` file with a _token_ from a user that has access to the organization to scan (listed below). Tokens should have admin:org or read:org access.
310311
1. Fill out the `.env` file with the desired _inactive_days_ value. This should be a whole positive number representing the amount of inactivity that you want for flagging stale repos.
311312
1. (Optional) Fill out the `.env` file with the [repository topics](https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/classifying-your-repository-with-topics) _exempt_topics_ that you want to filter out from the stale repos report. This should be a comma separated list of topics.
312313
1. (Optional) Fill out the `.env` file with the exact _organization_ that you want to search in
313314
1. (Optional) Fill out the `.env` file with the exact _URL_ of the GitHub Enterprise that you want to search in. Keep empty if you want to search in the public `github.com`.
314-
1. `pip install -r requirements.txt`
315-
1. Run `python3 ./stale_repos.py`, which will output a list of repositories and the length of their inactivity
315+
1. `uv sync`
316+
1. Run `uv run python3 ./stale_repos.py`, which will output a list of repositories and the length of their inactivity
316317
317318
## Local testing without Docker
318319
319320
1. Have Python v3.11 or greater installed
320-
1. `pip install -r requirements.txt -r requirements-test.txt`
321+
1. [Install uv](https://docs.astral.sh/uv/getting-started/installation/)
322+
1. `uv sync`
321323
1. `make lint`
322324
1. `make test`
323325

pyproject.toml

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
[project]
2+
name = "stale-repos"
3+
version = "1.0.0"
4+
description = "GitHub Action that finds stale repositories in a GitHub organization."
5+
requires-python = ">=3.11"
6+
dependencies = [
7+
"github3-py==4.0.1",
8+
"python-dateutil==2.9.0.post0",
9+
"python-dotenv==1.2.1",
10+
]
11+
12+
[dependency-groups]
13+
dev = [
14+
"black==26.1.0",
15+
"flake8==7.3.0",
16+
"isort==7.0.0",
17+
"mypy==1.19.1",
18+
"mypy-extensions==1.1.0",
19+
"pylint==4.0.4",
20+
"pytest==9.0.2",
21+
"pytest-cov==7.0.0",
22+
"types-python-dateutil==2.9.0.20260124",
23+
"types-requests==2.32.4.20260107",
24+
]

0 commit comments

Comments
 (0)