Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 9 additions & 15 deletions .github/workflows/test-crud.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ on:
- 'test/**'
- '.github/workflows/test-crud.yml'
- 'pyproject.toml'
- 'uv.lock'

jobs:
crud-tests:
Expand Down Expand Up @@ -47,28 +48,21 @@ jobs:
with:
python-version: '3.13'

- name: Install Poetry
uses: snok/install-poetry@v1
- name: Install uv
uses: astral-sh/setup-uv@v5
with:
virtualenvs-create: true
virtualenvs-in-project: true

- name: Cache Poetry virtualenv
uses: actions/cache@v4
with:
path: .venv
key: venv-${{ runner.os }}-py3.13-${{ hashFiles('pyproject.toml', 'poetry.lock') }}
restore-keys: |
venv-${{ runner.os }}-py3.13-
enable-cache: true
cache-dependency-glob: "uv.lock"

- name: Install dependencies
run: poetry install --with dev --no-interaction
# uv installs the default groups (dev + docs, see [tool.uv] in
# pyproject.toml), matching what `poetry install` pulled in before.
run: uv sync

- name: Create stub static asset directories
run: |
mkdir -p bases/rsptx/assignment_server_api/react
mkdir -p bases/rsptx/assignment_server_api/staticAssets

- name: Run tests
run: |
poetry run pytest -v --tb=short
run: uv run pytest -v --tb=short
94 changes: 67 additions & 27 deletions components/rsptx/build_tools/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,12 @@ def cli(config, verbose, all, core, service, clean, skip_pre, skip_tests):

with open("pyproject.toml") as f:
config.pyproject = toml.load(f)
config.version = config.pyproject["tool"]["poetry"]["version"]
# The root was migrated from poetry ([tool.poetry]) to PEP 621
# ([project]); fall back to the old location for safety.
config.version = (
config.pyproject.get("project", {}).get("version")
or config.pyproject["tool"]["poetry"]["version"]
)
Comment on lines +105 to +109

res = subprocess.run("docker info", shell=True, capture_output=True)
if res.returncode != 0:
Expand Down Expand Up @@ -432,37 +437,70 @@ def wheel(config):
f.write(res.stderr.decode(stdout_err_encoding))
f.write(res.stdout.decode(stdout_err_encoding))
sys.exit(1)
if os.path.isfile("pyproject.toml"):
if proj == "interactives":
# interactives ships a JS release only (built by its
# pre-build step above); no Python wheel is produced.
status[proj] = "[blue]JS only[/blue]"
lt.update(generate_wheel_table(status))
Comment on lines +440 to +444
elif os.path.isfile("pyproject.toml"):
status[proj] = "[grey62]building...[/grey62]"
lt.update(generate_wheel_table(status))
toml_stat = os.stat("pyproject.toml")
lock_stat = os.stat("poetry.lock")
if toml_stat.st_mtime > lock_stat.st_mtime:
with open("pyproject.toml") as f:
backend = (
toml.load(f)
.get("build-system", {})
.get("build-backend", "")
)
# During the poetry -> uv migration the repo may hold a
# mix of projects. uv-based projects use the hatchling
# backend and are built with `uv build`; legacy poetry
# projects still use `poetry build-project`.
if "hatchling" in backend:
# uv reads pyproject directly to build the wheel; no
# separate lock step is needed for the wheel's
# dependency metadata. The wheel lands in ./dist,
# where the service Dockerfile expects it.
res = subprocess.run(
["poetry", "--version"], capture_output=True
["uv", "build", "--wheel"], capture_output=True
)
# poetry 2.0 removed the --no-update flag (it is the default)
lock_opts = ["poetry", "lock"]
if "version 1" in res.stdout.decode(stdout_err_encoding):
lock_opts.append("--no-update")

res = subprocess.run(lock_opts, capture_output=True)
if res.returncode != 0:
status[proj] = (
f"[red]Fail[/red] probable dependency conflict see {projdir}/build.log"
else:
if os.path.isfile("poetry.lock"):
relock = (
os.stat("pyproject.toml").st_mtime
> os.stat("poetry.lock").st_mtime
)
else:
relock = True
if relock:
ver = subprocess.run(
["poetry", "--version"], capture_output=True
)
lt.update(generate_wheel_table(status))
if config.verbose:
console.print(
res.stderr.decode(stdout_err_encoding)
# poetry 2.0 removed the --no-update flag (it is the default)
lock_opts = ["poetry", "lock"]
if "version 1" in ver.stdout.decode(
stdout_err_encoding
):
lock_opts.append("--no-update")

res = subprocess.run(lock_opts, capture_output=True)
if res.returncode != 0:
status[proj] = (
f"[red]Fail[/red] probable dependency conflict see {projdir}/build.log"
)
else:
with open("build.log", "a") as f:
f.write(res.stderr.decode(stdout_err_encoding))
sys.exit(1)
res = subprocess.run(
["poetry", "build-project"], capture_output=True
)
lt.update(generate_wheel_table(status))
if config.verbose:
console.print(
res.stderr.decode(stdout_err_encoding)
)
else:
with open("build.log", "a") as f:
f.write(
res.stderr.decode(stdout_err_encoding)
)
sys.exit(1)
res = subprocess.run(
["poetry", "build-project"], capture_output=True
)
if res.returncode == 0:
status[proj] = "[green]Yes[/green]"
lt.update(generate_wheel_table(status))
Expand Down Expand Up @@ -684,8 +722,10 @@ def push(config):
)
if update_version.lower() in ["y", "yes"]:
new_version = input("Enter the new version number: ")
# uv version updates [project].version in the root pyproject.toml
# (the poetry equivalent was `poetry version <new>`).
subprocess.run(
["poetry", "version", new_version], capture_output=True, check=True
["uv", "version", new_version], capture_output=True, check=True
)
console.out("Version updated, don't forget to commit the change.")
# add a git tag for the new version
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ def __init__(
click_text: str,
loading_text: str,
*args,
**kwargs
**kwargs,
):
# pylint: disable=unused-argument
self._params = params
Expand Down
2 changes: 1 addition & 1 deletion components/rsptx/lti1p3/pylti1p3/oidc_login.py
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ def enable_check_cookies(
main_msg: t.Optional[str] = None,
click_msg: t.Optional[str] = None,
loading_msg: t.Optional[str] = None,
**kwargs
**kwargs,
) -> "OIDCLogin":
# pylint: disable=unused-argument
self._cookies_check = True
Expand Down
2 changes: 1 addition & 1 deletion docs/source/addbook.rst
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ Building the Book
~~~~~~~~~~~~~~~~~

1. Go to your ``$BOOK_PATH`` folder and clone a book. Lets take our simple overview book as an example. run the command ``git clone https://github.com/RunestoneInteractive/overview.git`` You should see a new folder called ``overview``
2. The over view book is already in the database, so the only thing we need to do is build it. ``cd overview`` and then run ``runestone build --all deploy`` If the command fails, make sure you have your virtual environment activated. You can do this by running ``poetry shell`` from the top level directory (rs).
2. The over view book is already in the database, so the only thing we need to do is build it. ``cd overview`` and then run ``runestone build --all deploy`` If the command fails, make sure you have your virtual environment activated. You can do this by running ``source .venv/bin/activate`` from the top level directory (rs).

This builds the book and deploys it to ``overview/published/overview`` This is the location that the Runestone server will look for it. Important: The book name and the folder name must match. So if you want to build a book called ``mybook`` then you need to clone it into a folder called ``mybook`` and then build it into ``mybook/published/mybook``.

Expand Down
18 changes: 9 additions & 9 deletions docs/source/building_servers.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,20 @@ You should have already:

#. :ref:`Cloned the source code<get-the-code>` (after forking it if you intend to contribute changes)

#. Set up Poetry.
#. Set up uv.

#. Copied ``sample.env`` to ``.env`` and edited the file -- make sure ``BOOK_PATH`` is set.

Now you are ready to install the required dependencies and build the servers:

4. Run ``poetry install --with=dev`` from the top level directory. This will install all of the dependencies for the project.
4. Run ``uv sync`` from the top level directory. This will install all of the dependencies for the project.

#. When that completes run ``poetry shell`` to start a poetry shell. You can verify that this worked correctly by running ``which rsmanage``. You should see a path something like `/path/to/rs/.venv/bin/rsmanage`. If you do not see this then you may need to run ``poetry shell`` again.
#. When that completes activate the virtual environment with ``source .venv/bin/activate``. You can verify that this worked correctly by running ``which rsmanage``. You should see a path something like `/path/to/rs/.venv/bin/rsmanage`. If you do not see this then you may need to run ``uv sync`` and activate again.

#. To leave the ``poetry`` shell, type ``exit``.
#. To leave the virtual environment, type ``deactivate``.

.. note::
Future instructions will make it clear which commands need to be run inside the poetry virtual environment by always including ``poetry run ...`` at the start of the command. This is what you will need to type if you are **NOT** in the poetry shell. If you activate the ``poetry shell``, you will be able to skip typing ``poetry run``. For example, to check the environmental variables, you would type ``poetry run rsmanage env`` if the poetry shell is not active; if the shell is active, you would just type ``rsmanage env``.
Future instructions will make it clear which commands need to be run inside the virtual environment by always including ``uv run ...`` at the start of the command. This is what you will need to type if you are **NOT** in the activated virtual environment. If you activate the virtual environment, you will be able to skip typing ``uv run``. For example, to check the environmental variables, you would type ``uv run rsmanage env`` if the virtual environment is not active; if the virtual environment is active, you would just type ``rsmanage env``.


7. Run the ``build`` script from the ``rs`` folder by doing ``build full``. The first step of this script will verify that you have all of your environment variables defined. It will then build the python wheels for all the runestone components and then build the docker servers. This will take a while.
Expand Down Expand Up @@ -95,7 +95,7 @@ The `build` script is a convenience script that will build the docker images for

.. note::

You either have to be in the poetry shell or run the script with ``poetry run build ...``.
You either have to be in the activated virtual environment or run the script with ``uv run build ...``.

There are several options that you can pass to the script. You can see them by running ``build --help``. The output of the help option is shown below:

Expand Down Expand Up @@ -139,7 +139,7 @@ Here is a bit more detail on how the script operates so you know what to expect:

#. If you pass the ``--clean`` option it will remove all of the containers and images before starting. This is useful if you are having trouble with the containers and want to start fresh.

#. Build the python wheels for all of the runestone components. This is done by running ``poetry build-project`` in each of the project directories. This will create a wheel file in the ``dist`` directory of each project. If there is a ``build.py`` file in the project folder it will be run before the wheel is built. This is useful for projects that need to build some assets before the wheel is built. such as the interactives or the assignment projects.
#. Build the python wheels for all of the runestone components. This is done by running ``uv build`` in each of the project directories. This will create a wheel file in the ``dist`` directory of each project. If there is a ``build.py`` file in the project folder it will be run before the wheel is built. This is useful for projects that need to build some assets before the wheel is built. such as the interactives or the assignment projects.

#. Build the docker images for the runestone servers. This is done by running ``docker compose build``. This will build the images for the runestone servers. If you pass the ``--all`` option it will also build the images for the author and worker servers. If you pass one or more ``--service <service>`` option(s) it will build for the services you specify.

Expand All @@ -159,8 +159,8 @@ To keep the servers up to date with the latest changes in the codebase, you will
The repository is under active development. It is a really good idea to keep your local copy up to date. You don't need to do this daily, but I would recommend weekly. To do this you will need to:

#. Pull the latest changes from the repo by running ``git pull``.
#. Run ``poetry install --with=dev`` to install any new dependencies.
#. Run ``poetry shell`` to start a poetry shell.
#. Run ``uv sync`` to install any new dependencies.
#. Activate the virtual environment with ``source .venv/bin/activate``.
#. Run ``build full`` to rebuild the servers, and check the database.
#. Run ``docker compose stop`` to start the servers.
#. Run ``docker compose up -d`` to start the servers.
Expand Down
2 changes: 1 addition & 1 deletion docs/source/database.rst
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ If you install postgresql locally you will need to do a few things to get it re
Database migrations
~~~~~~~~~~~~~~~~~~~

We use ``alembic`` to help track changes to the database schema. Note make sure that your run ``poetry shell`` and that you run the ``alembic`` command from the main ``rs`` folder. The first time you clone the project you should run ``alembic stamp head`` to let alembic know that the current state of the database is the head. This will allow you to run migrations in the future to ensure that your database schema is in sync with the ``models.py`` file. In the future when you pull changes You can run ``alembic upgrade head`` to apply all of the migrations to the current database. You can also run ``alembic history`` to see all of the migrations that have been applied to the database. The ``build checkdb`` command will also do its best to check that the database is up to date and will run the migrations for you if it can.
We use ``alembic`` to help track changes to the database schema. Note make sure that your run ``source .venv/bin/activate`` and that you run the ``alembic`` command from the main ``rs`` folder. The first time you clone the project you should run ``alembic stamp head`` to let alembic know that the current state of the database is the head. This will allow you to run migrations in the future to ensure that your database schema is in sync with the ``models.py`` file. In the future when you pull changes You can run ``alembic upgrade head`` to apply all of the migrations to the current database. You can also run ``alembic history`` to see all of the migrations that have been applied to the database. The ``build checkdb`` command will also do its best to check that the database is up to date and will run the migrations for you if it can.

If you make a change to the database model as part of your development work, please create a migration by running ``alembic revision --autogenerate -m "some message"``. This will create a new migration file in the ``alembic/versions`` directory. You can then edit this file to make sure that the migration does what you want. You can then run ``alembic upgrade head`` and this will apply the changes to your database. You should commit this and submit it as part of your PR. If you are not sure how to do this, please ask for help in the ``developer-forum`` channel on the Runestone discord server, **after** you have consulted the extensive documentation and tutorials that are available to help you learn how to use alembic.

Expand Down
Loading
Loading