Skip to content

Commit be40459

Browse files
authored
Use uv for dependency management and versioning (#553)
1 parent 8c8b07c commit be40459

17 files changed

+1061
-169
lines changed

.dockerignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
build
2+
ci
3+
logs/*
4+
.tox
5+
.venv

.github/workflows/container-image.yml

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -72,28 +72,30 @@ jobs:
7272
# There's a docker-compose.yml file in the mreg-cli repo that wants the image from ghcr.io,
7373
# but we want to use the newly built custom image
7474
run: docker tag mreg ghcr.io/unioslo/mreg:latest
75-
- name: Setup Python
76-
uses: actions/setup-python@v5
77-
with:
78-
python-version: 3.11
75+
- name: Install uv
76+
uses: astral-sh/setup-uv@v3
77+
- name: Set up Python
78+
run: uv python install 3.11
79+
- name: Install git
80+
run: |
81+
sudo apt-get update
82+
sudo apt-get install -y git
7983
- name: Install mreg-cli
8084
run: |
81-
curl -L -o mreg-cli https://github.com/unioslo/mreg-cli/releases/download/1.0.1/mreg-cli-ubuntu-latest-3.12
82-
chmod 0755 mreg-cli
83-
sudo mv mreg-cli /usr/bin/ # put it somewhere in $PATH
85+
git clone https://github.com/unioslo/mreg-cli.git
86+
cd mreg-cli
87+
uv venv
88+
uv pip install -e ".[dev]"
8489
- name: Run the tests
8590
run: |
86-
wget -nd https://github.com/unioslo/mreg-cli/archive/refs/heads/master.zip
87-
unzip master.zip
88-
cd mreg-cli-master
89-
cp data/mreg-cli.conf ~/.config/mreg-cli.conf
90-
pip install -r requirements-dev.txt
91-
ci/run_testsuite_and_record.sh
91+
cd mreg-cli
92+
. .venv/bin/activate
93+
uv run ci/run_testsuite_and_record.sh
9294
- name: Upload the log as an artifact
9395
uses: actions/upload-artifact@v4
9496
with:
9597
name: new_testsuite_log.json
96-
path: mreg-cli-master/ci/new_testsuite_log.json
98+
path: mreg-cli/ci/new_testsuite_log.json
9799

98100
test-with-curl:
99101
name: Test with curl
@@ -129,7 +131,7 @@ jobs:
129131
- name: Wait for mreg to create the database schema and start up
130132
run: sleep 10s
131133
- name: Create a user
132-
run: docker exec -t mreg /app/manage.py create_mreg_superuser --username test --password test123
134+
run: docker exec -t mreg uv run /app/manage.py create_mreg_superuser --username test --password test123
133135
- name: Authenticate using curl
134136
shell: bash
135137
run: |

.github/workflows/docker-image.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ jobs:
4343
--entry-point=bin/mreg-wrapper
4444
-m ./ci/manifest.scm
4545
- name: Upload artifact
46-
uses: actions/upload-artifact@v3
46+
uses: actions/upload-artifact@v4
4747
with:
4848
name: mreg-docker.tar.gz
4949
path: mreg-docker.tar.gz
@@ -57,7 +57,7 @@ jobs:
5757
contents: read
5858
steps:
5959
- name: Download artifact
60-
uses: actions/download-artifact@v3
60+
uses: actions/download-artifact@v4
6161
with:
6262
name: mreg-docker.tar.gz
6363
- name: Load image

.github/workflows/test.yml

Lines changed: 27 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ on:
88
types: [opened, reopened, synchronize]
99
workflow_dispatch:
1010

11+
env:
12+
UV_FROZEN: 1
13+
1114
name: CI
1215
jobs:
1316
test:
@@ -32,56 +35,44 @@ jobs:
3235
matrix:
3336
os: [ubuntu-latest]
3437
python-version:
35-
- "3.8"
36-
- "3.9"
3738
- "3.10"
3839
- "3.11"
3940
- "3.12"
4041
steps:
4142
- name: Checkout
4243
uses: actions/checkout@v4
43-
- name: Cache pip
44-
uses: actions/cache@v4
45-
with:
46-
path: ~/.cache/pip
47-
key: v1-pip-${{ runner.os }}-${{ matrix.python-version }}-${{ hashFiles('requirements-*.txt') }}
48-
restore-keys: |
49-
v1-pip-${{ runner.os }}-${{ matrix.python-version }}
50-
v1-pip-${{ runner.os }}
51-
v1-pip-
52-
- name: Install Python
53-
uses: actions/setup-python@v5
54-
with:
55-
python-version: ${{ matrix.python-version }}
44+
- name: Install uv
45+
uses: astral-sh/setup-uv@v3
46+
- name: Set up Python ${{ matrix.python-version }}
47+
run: uv python install ${{ matrix.python-version }}
5648
- name: Install dependencies
5749
run: |
5850
# Needed to build the native python-ldap extension.
5951
sudo apt-get update
6052
sudo apt-get -y install libsasl2-dev libldap2-dev
61-
python -m pip install --upgrade pip
62-
python -m pip install tox tox-gh-actions
63-
python -m pip install -r requirements-test.txt
53+
uv sync --group ci
6454
- name: Test with tox
65-
run: tox -r
55+
run: uv run tox -r
6656
env:
6757
MREG_DB_PASSWORD: postgres
6858
- name: Check migrations
6959
run: |
7060
export MREG_DB_NAME=mreg MREG_DB_USER=mreg MREG_DB_PASSWORD=postgres
71-
python manage.py makemigrations --check
72-
# - name: Export OpenAPI schema
73-
# run: python manage.py generateschema > openapi.yml
74-
# - name: Upload OpenAPI schema
75-
# if: matrix.python-version == '3.10'
76-
# uses: actions/upload-artifact@v3
77-
# with:
78-
# name: openapi.yml
79-
# path: openapi.yml
61+
uv run manage.py makemigrations --check
62+
# - name: Export OpenAPI schema
63+
# run: uv run manage.py generateschema > openapi.yml
64+
# - name: Upload OpenAPI schema
65+
# if: matrix.python-version == '3.10'
66+
# uses: actions/upload-artifact@v4
67+
# with:
68+
# name: openapi.yml
69+
# path: openapi.yml
8070
- name: Upload coverage
8171
uses: actions/upload-artifact@v4
8272
with:
8373
name: coverage-${{ matrix.python-version }}
8474
path: .coverage
75+
if-no-files-found: error
8576
include-hidden-files: true
8677

8778
coveralls:
@@ -93,34 +84,26 @@ jobs:
9384
matrix:
9485
os: [ubuntu-latest]
9586
python-version:
96-
- "3.8"
97-
- "3.9"
9887
- "3.10"
9988
- "3.11"
10089
- "3.12"
10190
steps:
10291
- name: Checkout
10392
uses: actions/checkout@v4
104-
- name: Cache pip
105-
uses: actions/cache@v4
106-
with:
107-
path: ~/.cache/pip
108-
key: v1-pip-${{ runner.os }}-${{ matrix.python-version }}
109-
restore-keys: |
110-
v1-pip-${{ runner.os }}
111-
v1-pip-
112-
- name: Install Python
113-
uses: actions/setup-python@v5
114-
with:
115-
python-version: ${{ matrix.python-version }}
93+
- name: Install uv
94+
uses: astral-sh/setup-uv@v3
95+
- name: Set up Python ${{ matrix.python-version }}
96+
run: uv python install ${{ matrix.python-version }}
11697
- name: Download coverage
11798
uses: actions/download-artifact@v4
11899
with:
119100
name: coverage-${{ matrix.python-version }}
120101
- name: Install Coveralls
121-
run: pip install coveralls
102+
run: |
103+
uv venv --no-project
104+
uv pip install coveralls
122105
- name: Run Coveralls
123-
run: coveralls
106+
run: uv run --no-project coveralls
124107
env:
125108
# Note: Set service name to work around
126109
# https://github.com/TheKevJames/coveralls-python/issues/252

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ wheels/
3030
.installed.cfg
3131
*.egg
3232
MANIFEST
33+
mreg/_version.py
3334

3435
# PyInstaller
3536
# Usually these files are written by a python script from a template

Dockerfile

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,25 +5,39 @@ ENV PYTHONDONTWRITEBYTECODE 1
55
ENV PYTHONUNBUFFERED 1
66

77
RUN apk update
8-
RUN apk add --virtual build-deps gcc python3-dev openldap-dev musl-dev
9-
RUN pip install --upgrade pip
10-
COPY requirements*.txt ./
11-
RUN pip wheel --no-cache-dir --wheel-dir /usr/src/mreg/wheels -r requirements.txt
8+
RUN apk add --virtual build-deps gcc python3-dev openldap-dev musl-dev git
9+
# Copy entire build context to the image.
10+
# In order to build the project, we need both the .git directory and project files.
11+
# However, we cannot mix files and directories in the COPY command, because
12+
# COPY will unpack the contents of source directories into the target directory,
13+
# and we need to keep the .git directory intact.
14+
# The workaround is to copy everything, but limit it with .dockerignore.
15+
COPY . .
16+
COPY --from=ghcr.io/astral-sh/uv:0.4.30 /uv /uvx /bin/
17+
RUN uv venv \
18+
&& uv sync --frozen --no-dev \
19+
&& uv export --no-hashes -o requirements.txt \
20+
&& uv run python -m ensurepip --upgrade \
21+
&& uv run python -m pip wheel --no-cache-dir --wheel-dir /usr/src/mreg/wheels -r requirements.txt \
22+
&& uv build --wheel --out-dir /usr/src/mreg/wheels
23+
24+
ENTRYPOINT [ "/bin/sh" ]
1225

1326
# final stage
1427
FROM alpine:3.18
1528
EXPOSE 8000
1629

17-
COPY requirements*.txt entrypoint* manage.py /app/
30+
COPY entrypoint* manage.py /app/
1831
COPY mreg /app/mreg/
1932
COPY mregsite /app/mregsite/
2033
RUN mkdir /app/logs
2134
COPY hostpolicy /app/hostpolicy/
2235
COPY --from=builder /usr/src/mreg/wheels /wheels
36+
COPY --from=ghcr.io/astral-sh/uv:0.4.30 /uv /uvx /bin/
2337
RUN apk update && apk upgrade \
24-
&& apk add python3 py3-pip libldap vim findutils \
25-
&& pip install --upgrade pip \
26-
&& pip install --no-cache /wheels/*
38+
&& apk add python3 libldap vim findutils \
39+
&& uv venv \
40+
&& uv pip install --no-cache /wheels/*
2741
RUN chmod a+x /app/entrypoint*
2842

2943
CMD /app/entrypoint.sh

README.md

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -48,41 +48,50 @@ For a full example, see `docker-compose.yml`.
4848

4949
#### Manually
5050

51-
[!TIP] Depending on your operating system, you may need to install additional packages to get the necessary dependencies for the project. At the very least you will probably require development packages for Python 3.
51+
> [!TIP]
52+
> Depending on your operating system, you may need to install additional packages to get the necessary dependencies for the project. At the very least you will probably require development packages for Python 3.
5253
5354
##### A step by step
5455

55-
Start by cloning the project from github. You need a terminal, `python3`, and access to a package manager that can install the necessary requirements from `requirements.txt`. We use pip.
56+
Start by cloning the project from github. You need a terminal and the [uv](https://docs.astral.sh/uv/) package manager.
5657

57-
When you've got your copy of the mreg directory, setup you virtual environment:
58+
> [!IMPORTANT]
59+
> mreg relies on PEP 735 dependency groups for development, which is [not supported by pip](https://github.com/pypa/pip/issues/12963) as of version 24.3.1.
60+
61+
When you've got your copy of the mreg directory, set up the venv and install the dependencies:
5862

5963
```bash
60-
> python3 -m venv venv
61-
> source venv/bin/activate
64+
> uv sync --frozen
6265
```
6366

64-
Then install the required packages:
67+
<details>
68+
<summary>Activating the venv (optional)</summary>
69+
70+
Optionally, you can also activate the created virtual environment. However, we will use `uv run` to run the commands in the virtual environment in this guide, which foregoes the need to activate the environment.
6571

6672
```bash
67-
> pip install -r requirements.txt
73+
. .venv/bin/activate
6874
```
6975

76+
Activating the venv allows you to run the commands with `python` instead of `uv run`.
77+
</details>
78+
7079
Perform database migrations:
7180

7281
```bash
73-
> python manage.py migrate
82+
> uv run manage.py migrate
7483
```
7584

7685
Load sample data from fixtures into the now migrated database:
7786

7887
```bash
79-
> python manage.py loaddata mreg/fixtures/fixtures.json
88+
> uv run manage.py loaddata mreg/fixtures/fixtures.json
8089
```
8190

8291
And finally, run the server:
8392

8493
```bash
85-
> python manage.py runserver
94+
> uv run manage.py runserver
8695
```
8796

8897
You should now be able to open up a browser and go to http://localhost:8000/hosts/ and see
@@ -99,7 +108,7 @@ the returned data.
99108
To run the tests for the system, simply run
100109
101110
```bash
102-
> python manage.py test
111+
> uv run manage.py test
103112
```
104113
105114
## Local Settings

entrypoint-test.sh

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
#!/bin/sh
22
set -e
33
cd /app
4-
./manage.py create_citext_extension --database template1
5-
./manage.py test --noinput --failfast
4+
uv run ./manage.py create_citext_extension --database template1
5+
uv run ./manage.py test --noinput --failfast

entrypoint.sh

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
#!/bin/sh
22
set -e
33
cd /app
4-
./manage.py create_citext_extension
5-
./manage.py migrate
6-
#./manage.py runserver 0.0.0.0:8000
4+
uv run ./manage.py create_citext_extension
5+
uv run ./manage.py migrate
6+
#uv run ./manage.py runserver 0.0.0.0:8000
77

88
# pass signals on to the gunicorn process
99
function sigterm()
@@ -14,5 +14,5 @@ function sigterm()
1414
trap sigterm SIGTERM
1515

1616
# doing it this way to be able to forward signals
17-
/usr/bin/gunicorn --workers=3 --bind=0.0.0.0 mregsite.wsgi --pid /var/run/gunicorn.pid &
17+
uv run gunicorn --workers=3 --bind=0.0.0.0 mregsite.wsgi --pid /var/run/gunicorn.pid &
1818
wait $!

mreg/__about__.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
"""Metadata for the mreg package."""
2+
3+
from __future__ import annotations
4+
5+
from importlib.metadata import version
6+
7+
__version__ = version("mreg")

0 commit comments

Comments
 (0)