Skip to content

Commit

Permalink
add dev container and tests (#19)
Browse files Browse the repository at this point in the history
* add devcontainer

* automate site generation and testing
  • Loading branch information
john0isaac authored Dec 9, 2024
1 parent 22e0459 commit 07a1b70
Show file tree
Hide file tree
Showing 10 changed files with 253 additions and 0 deletions.
5 changes: 5 additions & 0 deletions .devcontainer/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
ARG IMAGE="python:3.12"
FROM --platform=amd64 mcr.microsoft.com/devcontainers/${IMAGE}
RUN apt-get update \
&& export DEBIAN_FRONTEND=noninteractive \
&& apt-get -y install --no-install-recommends build-essential libssl-dev gdb cmake
39 changes: 39 additions & 0 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
// README at: https://github.com/devcontainers/templates/tree/main/src/python
{
"name": "Cookie Cutter - Render Engine",
// Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile
"build": {
"dockerfile": "Dockerfile",
"context": "..",
"args": {
"IMAGE": "python:3.12"
}
},
"postCreateCommand": ". .devcontainer/setup.sh",
"customizations": {
"vscode": {
"settings": {
"python.formatting.provider": "charliermarsh.ruff",
"python.testing.pytestEnabled": true,
"python.testing.pytestPath": "pytest",
"python.testing.unittestEnabled": false,
"python.editor.formatOnSave": true,
"python.editor.codeActionsOnSave": {"source.fixAll": true},
"python.testing.pytestArgs": [
"tests"
],
".markdownlint-cli2.ignores": [".gitignore"]

},
"extensions": [
"ms-python.python",
"charliermarsh.ruff",
"GitHub.vscode-github-actions",
"yzhang.markdown-all-in-one",
"DavidAnson.vscode-markdownlint",
"ms-vscode.makefile-tools"
]
}
}
}
6 changes: 6 additions & 0 deletions .devcontainer/setup.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
python -m pip install --user --upgrade pip
python -m venv .venv
source .venv/bin/activate
python -m pip install pip-tools
python -m piptools compile --upgrade -o requirements.txt requirements.in
python -m pip install -r requirements-dev.txt
28 changes: 28 additions & 0 deletions .github/workflows/devcontainer-ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
name: Check Dev Container

on:
push:
branches: [ main ]
paths:
- ".devcontainer/**"
- ".github/workflows/devcontainer-ci.yaml"
pull_request:
branches: [ main ]
paths:
- ".devcontainer/**"
- ".github/workflows/devcontainer-ci.yaml"

permissions:
contents: read

jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Use Node.js 20.x
uses: actions/setup-node@v4
with:
node-version: 20.x
- run: npm install -g @devcontainers/cli
- run: devcontainer build --config ./.devcontainer/devcontainer.json --workspace-folder "$(pwd)"
28 changes: 28 additions & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
name: PyTest
on:
workflow_call:
workflow_dispatch:
push:
branches:
- main
pull_request:
branches:
- main

jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.10", "3.11", "3.12", "3.13"]
fail-fast: true
steps:
- uses: actions/checkout@v4
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: python -m pip install --upgrade pip -r requirements-dev.txt
- name: Run tests
run: python tests/test_template.py
4 changes: 4 additions & 0 deletions requirements-dev.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
pip-tools
pytest

-r requirements.txt
1 change: 1 addition & 0 deletions requirements.in
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
cookiecutter
50 changes: 50 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
#
# This file is autogenerated by pip-compile with Python 3.12
# by the following command:
#
# pip-compile --output-file=requirements.txt requirements.in
#
arrow==1.3.0
# via cookiecutter
binaryornot==0.4.4
# via cookiecutter
certifi==2024.8.30
# via requests
chardet==5.2.0
# via binaryornot
charset-normalizer==3.4.0
# via requests
click==8.1.7
# via cookiecutter
cookiecutter==2.6.0
# via -r requirements.in
idna==3.10
# via requests
jinja2==3.1.4
# via cookiecutter
markdown-it-py==3.0.0
# via rich
markupsafe==3.0.2
# via jinja2
mdurl==0.1.2
# via markdown-it-py
pygments==2.18.0
# via rich
python-dateutil==2.9.0.post0
# via arrow
python-slugify==8.0.4
# via cookiecutter
pyyaml==6.0.2
# via cookiecutter
requests==2.32.3
# via cookiecutter
rich==13.9.4
# via cookiecutter
six==1.17.0
# via python-dateutil
text-unidecode==1.3
# via python-slugify
types-python-dateutil==2.9.0.20241206
# via arrow
urllib3==2.2.3
# via requests
4 changes: 4 additions & 0 deletions tests/pytest.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[pytest]
python_files = test_*.py
python_classes = [A-Z]*Test
python_functions = test_*
88 changes: 88 additions & 0 deletions tests/test_template.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
"""
Test the Cookiecutter template.
"""
from cookiecutter.generate import generate_context
from cookiecutter.main import cookiecutter
from pathlib import Path
from shlex import split
from subprocess import run
from venv import create

import pytest


@pytest.fixture(scope="session")
def template() -> Path:
""" The template under test.
"""
return Path(__file__).resolve().parents[1]


@pytest.fixture(scope="module")
def tmpdir(tmp_path_factory) -> Path:
""" Test directory.
"""
return tmp_path_factory.mktemp("test_template")


@pytest.fixture(scope="module")
def context(template) -> dict:
""" Template context for testing.
"""
context = generate_context(template.joinpath("cookiecutter.json"))
context["cookiecutter"].update({
"project_slug": "slugify"
})
return context["cookiecutter"]


@pytest.fixture(scope="module")
def project(tmpdir, template, context) -> Path:
""" Create a test project from the Cookiecutter template.
"""
cookiecutter(str(template), no_input=True, output_dir=tmpdir, extra_context=context)
return tmpdir / context["project_slug"]


@pytest.fixture
def python(tmp_path):
""" Create a Python virtual environment for testing.
"""
venv = tmp_path / ".venv"
create(venv, with_pip=True)
return venv / "bin" / "python"


def test_project(project):
""" Verify that the project was created correctly.
"""
# Just a basic sanity test.
assert len(list(project.iterdir())) == 4
return


@pytest.fixture
def install_render_engine_cli(python):
install_cli = "pip install render_engine[cli]"
install_args = split(f"{python} -m {install_cli}")
install_process = run(install_args)
assert install_process.returncode == 0


def test_site_generation(context, project, python, install_render_engine_cli):
generate_site = "render_engine build app:app"
generate_args = split(f"{python} -m {generate_site}")
generate_process = run(generate_args, cwd=project)
assert generate_process.returncode == 0


# Make the script executable.

if __name__ == "__main__":
raise SystemExit(pytest.main([__file__]))

0 comments on commit 07a1b70

Please sign in to comment.